Note: I originally filed this as a Node.js 22 bug. After deeper investigation, the real root cause is the same as #344 — middleware/proxy intercepting /.well-known/workflow/* and consuming the request body before the workflow executor reads it. I'm leaving this open as a DX issue because the current error makes it nearly impossible to diagnose without prior knowledge.
Symptom
When triggering a workflow via start() in a Next.js App Router app, the API route returns a runId successfully (HTTP 200), but the workflow never executes. The dev server logs:
[local world] Queue operation failed: TypeError: fetch failed
at ignore-listed frames {
[cause]: TypeError: Cannot perform ArrayBuffer.prototype.slice on a detached ArrayBuffer
at ArrayBuffer.slice (<anonymous>)
}
The run sits in status: "pending" forever (visible in .workflow-data/runs/).
Actual Root Cause
The Next.js middleware (middleware.ts) or proxy (proxy.ts in Next.js 16) intercepts the WDK's internal POST /.well-known/workflow/v1/flow request. When the middleware reads/clones the request body for authentication or any other reason, the underlying ArrayBuffer is transferred (detached). When the request finally reaches the workflow route handler, the executor's internal fetch tries to read the body and fails with the detached ArrayBuffer error.
This is exactly the issue from #344 (closed), but the error message points users in completely the wrong direction:
- Mentions
Node.js/ArrayBuffer internals — implies a runtime bug
- No mention of middleware, proxy, or
.well-known/workflow/
- Doesn't appear during the initial
POST /api/workflows/... call — it appears asynchronously after the API responds 200, in a background queue log line
Why this hits Next.js 16 users especially hard
Next.js 16 introduced proxy.ts as the replacement for middleware.ts. The default scaffolded proxy.ts matcher commonly looks like:
export const config = {
matcher: [
'/((?!api|invites|public|assets|_next/static|_next/image|favicon.ico).*)',
],
}
Notice .well-known/workflow is not in the exclusion list. Existing WDK docs (Configure proxy handler) mention this but:
- The page title says "if applicable" — easy to skip when you don't think you have a proxy
- The Next.js 16
proxy.ts naming is new — Next 15 users coming back may not realize their existing config now applies under a new name
- There's no runtime hint linking the cryptic error to this docs page
Proposed fixes
1. Better error message (highest impact)
When the workflow executor fails to read the request body, detect the detached-ArrayBuffer case in @workflow/world-local/dist/queue.js and @workflow/core and rethrow with actionable context:
[workflow] Failed to deliver message to /.well-known/workflow/v1/flow.
The request body was detached before reaching the executor — this almost
always means a Next.js middleware/proxy is intercepting the route.
Fix: add `.well-known/workflow` to your middleware matcher exclusion list.
See: https://useworkflow.dev/docs/getting-started/next#configure-proxy-handler-if-applicable
The check can be as simple as if (err.cause?.message?.includes('detached ArrayBuffer')) in the queue's .catch() handler.
2. Runtime sanity check on withWorkflow() startup
In dev mode, withWorkflow() could:
- Read the project's
middleware.ts / proxy.ts (if present)
- Parse the
config.matcher regex
- Test if
/.well-known/workflow/v1/flow would match the matcher
- If yes → emit a warning at server start time:
⚠ Detected middleware/proxy matcher that includes `.well-known/workflow/*`.
Workflows will fail with cryptic ArrayBuffer errors until this is excluded.
Update your matcher to exclude `.well-known/workflow`.
This catches the issue before the user even tries to run a workflow.
3. Docs prominence
- Promote the proxy-exclusion section from "if applicable" to a required step in the Next.js getting-started guide
- Add a dedicated callout for Next.js 16 (
proxy.ts naming change)
- Add a troubleshooting page entry for the exact error string
Cannot perform ArrayBuffer.prototype.slice on a detached ArrayBuffer → links to the fix
Reproduction
- Next.js 16 App Router project with
workflow@5.0.0-beta.5
proxy.ts matcher: '/((?!api|...).*)' (does NOT exclude .well-known/workflow)
- Trigger any workflow via
start() from an API route
- Workflow returns
runId (200), but stays pending forever
- Console shows the cryptic ArrayBuffer error
Fix verified working:
// proxy.ts
export const config = {
matcher: [
'/((?!api|...|\\.well-known/workflow|_next/static|...).*)',
// ^^^^^^^^^^^^^^^^^^ add this
],
}
Environment
- Node.js: tested on both 20.20.2 and 22.18.0 — same error, same fix
- workflow: 5.0.0-beta.5 (also reproduced on 4.2.4)
- @workflow/next: 5.0.0-beta.5
- Next.js: 16.2.0 (App Router,
proxy.ts)
Related
Happy to send a PR for fix #1 (the error message) if maintainers are open to it.
Symptom
When triggering a workflow via
start()in a Next.js App Router app, the API route returns arunIdsuccessfully (HTTP 200), but the workflow never executes. The dev server logs:The run sits in
status: "pending"forever (visible in.workflow-data/runs/).Actual Root Cause
The Next.js middleware (
middleware.ts) or proxy (proxy.tsin Next.js 16) intercepts the WDK's internalPOST /.well-known/workflow/v1/flowrequest. When the middleware reads/clones the request body for authentication or any other reason, the underlyingArrayBufferis transferred (detached). When the request finally reaches the workflow route handler, the executor's internal fetch tries to read the body and fails with the detached ArrayBuffer error.This is exactly the issue from #344 (closed), but the error message points users in completely the wrong direction:
Node.js/ArrayBufferinternals — implies a runtime bug.well-known/workflow/POST /api/workflows/...call — it appears asynchronously after the API responds 200, in a background queue log lineWhy this hits Next.js 16 users especially hard
Next.js 16 introduced
proxy.tsas the replacement formiddleware.ts. The default scaffoldedproxy.tsmatcher commonly looks like:Notice
.well-known/workflowis not in the exclusion list. Existing WDK docs (Configure proxy handler) mention this but:proxy.tsnaming is new — Next 15 users coming back may not realize their existing config now applies under a new nameProposed fixes
1. Better error message (highest impact)
When the workflow executor fails to read the request body, detect the detached-ArrayBuffer case in
@workflow/world-local/dist/queue.jsand@workflow/coreand rethrow with actionable context:The check can be as simple as
if (err.cause?.message?.includes('detached ArrayBuffer'))in the queue's.catch()handler.2. Runtime sanity check on
withWorkflow()startupIn dev mode,
withWorkflow()could:middleware.ts/proxy.ts(if present)config.matcherregex/.well-known/workflow/v1/flowwould match the matcherThis catches the issue before the user even tries to run a workflow.
3. Docs prominence
proxy.tsnaming change)Cannot perform ArrayBuffer.prototype.slice on a detached ArrayBuffer→ links to the fixReproduction
workflow@5.0.0-beta.5proxy.tsmatcher:'/((?!api|...).*)'(does NOT exclude.well-known/workflow)start()from an API routerunId(200), but stayspendingforeverFix verified working:
Environment
proxy.ts)Related
Happy to send a PR for fix #1 (the error message) if maintainers are open to it.