Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .changeset/giant-mirrors-find.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
6 changes: 6 additions & 0 deletions .changeset/node24-clerk-request-signal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@clerk/backend': patch
'@clerk/react-router': patch
---

Fix `Request` cloning to omit cross-realm `AbortSignal`. Node 24's bundled undici tightened the `instanceof AbortSignal` check on `RequestInit.signal`, which broke cloning of framework-specific requests such as `NextRequest` (in `@clerk/backend`'s `ClerkRequest`) and any subclassed Request passed through `patchRequest` (in `@clerk/react-router`).
1 change: 1 addition & 0 deletions .claude/scheduled_tasks.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"sessionId":"5e44597f-987b-4e95-99b1-fe9b66b105a1","pid":12702,"acquiredAt":1776826211795}
2 changes: 1 addition & 1 deletion .github/actions/init-blacksmith/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ inputs:
node-version:
description: 'The node version to use'
required: false
default: '22'
default: '24.15.0'
playwright-enabled:
description: 'Enable Playwright?'
required: false
Expand Down
2 changes: 1 addition & 1 deletion .github/actions/init/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ inputs:
node-version:
description: 'The node version to use'
required: false
default: '22'
default: '24.15.0'
playwright-enabled:
description: 'Enable Playwright?'
required: false
Expand Down
9 changes: 6 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,10 @@ jobs:
fail-fast: false
matrix:
include:
- node-version: 22
- node-version: 24.15.0
test-filter: "**"
filter-label: "**"
- node-version: 20.19.0
test-filter: "**"
filter-label: "**"

Expand Down Expand Up @@ -257,7 +260,7 @@ jobs:
- name: Run Typedoc tests
run: |
# Only run Typedoc tests for one matrix version and main test run
if [ "${{ matrix.node-version }}" == "22" ] && [ "${{ matrix.test-filter }}" = "**" ]; then
if [ "${{ matrix.node-version }}" == "24.15.0" ] && [ "${{ matrix.test-filter }}" = "**" ]; then
pnpm turbo run //#test:typedoc
fi
env:
Expand Down Expand Up @@ -501,7 +504,7 @@ jobs:
uses: ./.github/actions/init-blacksmith
with:
turbo-enabled: true
node-version: 22
node-version: 24.15.0
turbo-signature: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }}
turbo-summarize: ${{ env.TURBO_SUMMARIZE }}
turbo-team: ${{ vars.TURBO_TEAM }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -524,7 +524,7 @@ jobs:

strategy:
matrix:
version: [22] # NOTE: 18 is cached in the main release workflow
version: [24] # NOTE: 20 is cached in the main release workflow

steps:
- name: Checkout Repo
Expand Down
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
22.11.0
24.15.0
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@
},
"packageManager": "pnpm@10.33.0+sha512.10568bb4a6afb58c9eb3630da90cc9516417abebd3fabbe6739f0ae795728da1491e9db5a544c76ad8eb7570f5c4bb3d6c637b2cb41bfdcdb47fa823c8649319",
"engines": {
"node": ">=22.11.0",
"node": ">=24.15.0",
"pnpm": ">=10.17.1"
},
"pnpm": {
Expand Down
20 changes: 19 additions & 1 deletion packages/backend/src/tokens/clerkRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,25 @@ class ClerkRequest extends Request {
// https://github.com/nodejs/undici/issues/2155
// https://github.com/nodejs/undici/blob/7153a1c78d51840bbe16576ce353e481c3934701/lib/fetch/request.js#L854
const url = typeof input !== 'string' && 'url' in input ? input.url : String(input);
super(url, init || typeof input === 'string' ? undefined : input);
// When cloning a Request by passing it as init, hide its `signal`. Undici's
// Request constructor in Node 24 performs a strict instanceof check on the
// signal and rejects ones from a different realm (e.g. NextRequest). Using a
// Proxy keeps property access lazy so environments that don't implement
// optional getters (e.g. Cloudflare Workers' Request lacks `cache`) still work.
let cloneInit: RequestInit | undefined;
if (init) {
cloneInit = init;
} else if (typeof input !== 'string') {
cloneInit = new Proxy(input as Request, {
get(target, prop) {
if (prop === 'signal') {
return undefined;
}
return Reflect.get(target, prop, target);
},
}) as unknown as RequestInit;
}
super(url, cloneInit);
this.clerkUrl = this.deriveUrlFromHeaders(this);
this.cookies = this.parseCookies(this);
}
Expand Down
4 changes: 3 additions & 1 deletion packages/react-router/src/server/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,12 +135,14 @@ export const wrapWithClerkState = (data: any) => {
* @internal
*/
export const patchRequest = (request: Request) => {
// Omit `signal` from the clone: Node 24's bundled undici tightened the
// instanceof AbortSignal check, which rejects cross-realm signals (e.g.
// those carried by framework Request subclasses).
const clonedRequest = new Request(request.url, {
headers: request.headers,
method: request.method,
redirect: request.redirect,
cache: request.cache,
signal: request.signal,
});

// If duplex is not set, set it to 'half' to avoid duplex issues with unidici
Expand Down
Loading