From 9a05560995c61e270a3d23ab1ddd65378f549239 Mon Sep 17 00:00:00 2001 From: Pranay Prakash Date: Thu, 14 May 2026 11:14:00 -0700 Subject: [PATCH 1/3] fix(world-local): explain detached ArrayBuffer proxy failures --- .changeset/sixty-plants-shout.md | 5 +++ docs/content/docs/v4/getting-started/next.mdx | 6 ++- docs/content/docs/v5/getting-started/next.mdx | 6 ++- packages/world-local/src/queue.test.ts | 27 ++++++++++++ packages/world-local/src/queue.ts | 42 ++++++++++++++++++- 5 files changed, 81 insertions(+), 5 deletions(-) create mode 100644 .changeset/sixty-plants-shout.md diff --git a/.changeset/sixty-plants-shout.md b/.changeset/sixty-plants-shout.md new file mode 100644 index 0000000000..53bd9fc0ef --- /dev/null +++ b/.changeset/sixty-plants-shout.md @@ -0,0 +1,5 @@ +--- +'@workflow/world-local': patch +--- + +Improve the local queue error message when a Next.js proxy intercepts workflow routes. diff --git a/docs/content/docs/v4/getting-started/next.mdx b/docs/content/docs/v4/getting-started/next.mdx index c9785d4aec..ae7ed0f7c3 100644 --- a/docs/content/docs/v4/getting-started/next.mdx +++ b/docs/content/docs/v4/getting-started/next.mdx @@ -77,7 +77,7 @@ To enable helpful hints in your IDE, setup the workflow plugin in `tsconfig.json - ### Configure Proxy Handler (if applicable) + ### Configure Proxy Handler @@ -85,7 +85,9 @@ If your Next.js app has a [proxy handler](https://nextjs.org/docs/app/api-refere (formerly known as "middleware"), you'll need to update the matcher pattern to exclude Workflow's internal paths to prevent the proxy handler from running on them. -Add `.well-known/workflow/*` to your middleware's exclusion list: +If you see `[local world] Queue operation failed` with `Cannot perform ArrayBuffer.prototype.slice on a detached ArrayBuffer`, your proxy matcher is still intercepting Workflow's internal `POST /.well-known/workflow/v1/flow` request. This is especially easy to miss in Next.js 16, where `proxy.ts` replaced `middleware.ts`. + +Add `.well-known/workflow/*` to your matcher exclusion list: ```typescript title="proxy.ts" lineNumbers import { NextResponse } from "next/server"; diff --git a/docs/content/docs/v5/getting-started/next.mdx b/docs/content/docs/v5/getting-started/next.mdx index c9785d4aec..ae7ed0f7c3 100644 --- a/docs/content/docs/v5/getting-started/next.mdx +++ b/docs/content/docs/v5/getting-started/next.mdx @@ -77,7 +77,7 @@ To enable helpful hints in your IDE, setup the workflow plugin in `tsconfig.json - ### Configure Proxy Handler (if applicable) + ### Configure Proxy Handler @@ -85,7 +85,9 @@ If your Next.js app has a [proxy handler](https://nextjs.org/docs/app/api-refere (formerly known as "middleware"), you'll need to update the matcher pattern to exclude Workflow's internal paths to prevent the proxy handler from running on them. -Add `.well-known/workflow/*` to your middleware's exclusion list: +If you see `[local world] Queue operation failed` with `Cannot perform ArrayBuffer.prototype.slice on a detached ArrayBuffer`, your proxy matcher is still intercepting Workflow's internal `POST /.well-known/workflow/v1/flow` request. This is especially easy to miss in Next.js 16, where `proxy.ts` replaced `middleware.ts`. + +Add `.well-known/workflow/*` to your matcher exclusion list: ```typescript title="proxy.ts" lineNumbers import { NextResponse } from "next/server"; diff --git a/packages/world-local/src/queue.test.ts b/packages/world-local/src/queue.test.ts index 8f0b4f4491..8b9d2d1e8c 100644 --- a/packages/world-local/src/queue.test.ts +++ b/packages/world-local/src/queue.test.ts @@ -48,6 +48,8 @@ describe('queue timeout re-enqueue', () => { afterEach(async () => { await localQueue.close(); + vi.restoreAllMocks(); + vi.unstubAllGlobals(); }); it('createQueueHandler returns 200 with timeoutSeconds in the body', async () => { @@ -166,4 +168,29 @@ describe('queue timeout re-enqueue', () => { // setTimeout should NOT have been called for timeoutSeconds: 0 expect(mockSetTimeout).not.toHaveBeenCalled(); }); + + it('logs actionable guidance for detached ArrayBuffer proxy failures', async () => { + const consoleError = vi.spyOn(console, 'error').mockImplementation(() => {}); + const fetchError = new TypeError('fetch failed'); + (fetchError as TypeError & { cause?: unknown }).cause = new TypeError( + 'Cannot perform ArrayBuffer.prototype.slice on a detached ArrayBuffer' + ); + vi.stubGlobal('fetch', vi.fn().mockRejectedValue(fetchError)); + + await localQueue.queue('__wkf_step_test' as any, stepPayload); + + await vi.waitFor(() => { + expect(consoleError).toHaveBeenCalledWith( + expect.stringContaining( + '[local world] Queue operation failed: detected "Cannot perform ArrayBuffer.prototype.slice on a detached ArrayBuffer"' + ), + expect.objectContaining({ + queueName: '__wkf_step_test', + runId: 'run_01ABC', + stepId: 'step_01ABC', + originalError: fetchError, + }) + ); + }); + }); }); diff --git a/packages/world-local/src/queue.ts b/packages/world-local/src/queue.ts index 5a7bf6d7f7..8cce1e553f 100644 --- a/packages/world-local/src/queue.ts +++ b/packages/world-local/src/queue.ts @@ -66,6 +66,30 @@ export type LocalQueue = Queue & { ): void; }; +const DETACHED_ARRAYBUFFER_ERROR = + 'Cannot perform ArrayBuffer.prototype.slice on a detached ArrayBuffer'; +const PROXY_HANDLER_DOCS_URL = + 'https://useworkflow.dev/docs/getting-started/next#configure-proxy-handler'; + +function isDetachedArrayBufferQueueError(error: unknown): boolean { + let current = error; + const visited = new Set(); + + while (current && typeof current === 'object' && !visited.has(current)) { + visited.add(current); + if ( + 'message' in current && + typeof current.message === 'string' && + current.message.includes(DETACHED_ARRAYBUFFER_ERROR) + ) { + return true; + } + current = 'cause' in current ? current.cause : undefined; + } + + return false; +} + function getQueueRoute(queueName: ValidQueueName): { pathname: 'flow' | 'step'; prefix: '__wkf_step_' | '__wkf_workflow_'; @@ -240,7 +264,23 @@ export function createQueue(config: Partial): LocalQueue { const isAbortError = err?.name === 'AbortError' || err?.name === 'ResponseAborted'; if (!isAbortError) { - console.error('[local world] Queue operation failed:', err); + if (isDetachedArrayBufferQueueError(err)) { + console.error( + `[local world] Queue operation failed: detected "${DETACHED_ARRAYBUFFER_ERROR}". ` + + "This usually means a Next.js proxy/middleware consumed Workflow's internal " + + 'request before the executor could read it. Exclude `/.well-known/workflow/*` ' + + `from your matcher. See ${PROXY_HANDLER_DOCS_URL}`, + { + queueName, + messageId, + ...(runId && { runId }), + ...(stepId && { stepId }), + originalError: err, + } + ); + } else { + console.error('[local world] Queue operation failed:', err); + } } }) .finally(() => { From e0c425d031d1d43b977a7656f95bfd671367a175 Mon Sep 17 00:00:00 2001 From: Pranay Prakash Date: Thu, 14 May 2026 11:22:22 -0700 Subject: [PATCH 2/3] fix(docs): make proxy handler anchor navigable --- docs/content/docs/v4/getting-started/next.mdx | 10 +--------- docs/content/docs/v5/getting-started/next.mdx | 10 +--------- packages/world-local/src/queue.ts | 2 +- 3 files changed, 3 insertions(+), 19 deletions(-) diff --git a/docs/content/docs/v4/getting-started/next.mdx b/docs/content/docs/v4/getting-started/next.mdx index ae7ed0f7c3..4d34f0bea8 100644 --- a/docs/content/docs/v4/getting-started/next.mdx +++ b/docs/content/docs/v4/getting-started/next.mdx @@ -74,12 +74,7 @@ To enable helpful hints in your IDE, setup the workflow plugin in `tsconfig.json - - - - ### Configure Proxy Handler - - +## Configure Proxy Handler If your Next.js app has a [proxy handler](https://nextjs.org/docs/app/api-reference/file-conventions/proxy) (formerly known as "middleware"), you'll need to update the matcher pattern to exclude Workflow's @@ -109,9 +104,6 @@ export const config = { ``` This ensures that internal Workflow paths are not intercepted by your middleware, which could interfere with workflow execution and resumption. - - - diff --git a/docs/content/docs/v5/getting-started/next.mdx b/docs/content/docs/v5/getting-started/next.mdx index ae7ed0f7c3..4d34f0bea8 100644 --- a/docs/content/docs/v5/getting-started/next.mdx +++ b/docs/content/docs/v5/getting-started/next.mdx @@ -74,12 +74,7 @@ To enable helpful hints in your IDE, setup the workflow plugin in `tsconfig.json - - - - ### Configure Proxy Handler - - +## Configure Proxy Handler If your Next.js app has a [proxy handler](https://nextjs.org/docs/app/api-reference/file-conventions/proxy) (formerly known as "middleware"), you'll need to update the matcher pattern to exclude Workflow's @@ -109,9 +104,6 @@ export const config = { ``` This ensures that internal Workflow paths are not intercepted by your middleware, which could interfere with workflow execution and resumption. - - - diff --git a/packages/world-local/src/queue.ts b/packages/world-local/src/queue.ts index 8cce1e553f..7ac0277dad 100644 --- a/packages/world-local/src/queue.ts +++ b/packages/world-local/src/queue.ts @@ -69,7 +69,7 @@ export type LocalQueue = Queue & { const DETACHED_ARRAYBUFFER_ERROR = 'Cannot perform ArrayBuffer.prototype.slice on a detached ArrayBuffer'; const PROXY_HANDLER_DOCS_URL = - 'https://useworkflow.dev/docs/getting-started/next#configure-proxy-handler'; + 'https://workflow-sdk.dev/docs/getting-started/next#configure-proxy-handler'; function isDetachedArrayBufferQueueError(error: unknown): boolean { let current = error; From 23b8b4eb094ab7df71bee6be8f1ac239cd90be55 Mon Sep 17 00:00:00 2001 From: Pranay Prakash Date: Thu, 14 May 2026 11:24:02 -0700 Subject: [PATCH 3/3] fix(docs): open accordions for hash links --- docs/components/ui/accordion.tsx | 34 ++++++++++++++++++- docs/content/docs/v4/getting-started/next.mdx | 10 +++++- docs/content/docs/v5/getting-started/next.mdx | 10 +++++- 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/docs/components/ui/accordion.tsx b/docs/components/ui/accordion.tsx index 51015b1232..d1ef142f26 100644 --- a/docs/components/ui/accordion.tsx +++ b/docs/components/ui/accordion.tsx @@ -1,5 +1,6 @@ 'use client'; +import { useEffect, useRef } from 'react'; import { ChevronDownIcon } from 'lucide-react'; import { Accordion as AccordionPrimitive } from 'radix-ui'; import type * as React from 'react'; @@ -9,7 +10,38 @@ import { cn } from '@/lib/utils'; function Accordion({ ...props }: React.ComponentProps) { - return ; + const ref = useRef(null); + + useEffect(() => { + const syncHashTarget = () => { + const hash = window.location.hash.slice(1); + if (!hash || !ref.current) return; + + const target = document.getElementById(decodeURIComponent(hash)); + if (!target || !ref.current.contains(target)) return; + + const item = target.closest('[data-slot="accordion-item"]'); + const trigger = item?.querySelector( + '[data-slot="accordion-trigger"]' + ); + + if (item?.dataset.state !== 'open') { + trigger?.click(); + } + + requestAnimationFrame(() => { + target.scrollIntoView({ block: 'start' }); + }); + }; + + syncHashTarget(); + window.addEventListener('hashchange', syncHashTarget); + return () => { + window.removeEventListener('hashchange', syncHashTarget); + }; + }, []); + + return ; } function AccordionItem({ diff --git a/docs/content/docs/v4/getting-started/next.mdx b/docs/content/docs/v4/getting-started/next.mdx index 4d34f0bea8..0e8ea51391 100644 --- a/docs/content/docs/v4/getting-started/next.mdx +++ b/docs/content/docs/v4/getting-started/next.mdx @@ -74,7 +74,12 @@ To enable helpful hints in your IDE, setup the workflow plugin in `tsconfig.json -## Configure Proxy Handler + + + +

Configure Proxy Handler (if applicable)

+
+ If your Next.js app has a [proxy handler](https://nextjs.org/docs/app/api-reference/file-conventions/proxy) (formerly known as "middleware"), you'll need to update the matcher pattern to exclude Workflow's @@ -104,6 +109,9 @@ export const config = { ``` This ensures that internal Workflow paths are not intercepted by your middleware, which could interfere with workflow execution and resumption. + +
+
diff --git a/docs/content/docs/v5/getting-started/next.mdx b/docs/content/docs/v5/getting-started/next.mdx index 4d34f0bea8..0e8ea51391 100644 --- a/docs/content/docs/v5/getting-started/next.mdx +++ b/docs/content/docs/v5/getting-started/next.mdx @@ -74,7 +74,12 @@ To enable helpful hints in your IDE, setup the workflow plugin in `tsconfig.json -## Configure Proxy Handler + + + +

Configure Proxy Handler (if applicable)

+
+ If your Next.js app has a [proxy handler](https://nextjs.org/docs/app/api-reference/file-conventions/proxy) (formerly known as "middleware"), you'll need to update the matcher pattern to exclude Workflow's @@ -104,6 +109,9 @@ export const config = { ``` This ensures that internal Workflow paths are not intercepted by your middleware, which could interfere with workflow execution and resumption. + +
+