vercel/ai · error

Workflow run ID not found in "x-workflow-run-id" response he

Error message

Workflow run ID not found in "x-workflow-run-id" response header

What it means

After a successful POST, the chat transport expects the server to return the workflow run ID in the 'x-workflow-run-id' response header. If the header is missing, the client cannot track or reconnect to the workflow run, so it throws.

Source

Thrown at packages/workflow/src/workflow-chat-transport.ts:325

    const response = await this.fetch(url, {
      method: 'POST',
      body: JSON.stringify(
        requestConfig?.body ?? { messages, ...options.body },
      ),
      headers: requestConfig?.headers,
      credentials: requestConfig?.credentials,
      signal: abortSignal,
    });

    if (!response.ok || !response.body) {
      throw new Error(
        `Failed to fetch chat: ${response.status} ${await response.text()}`,
      );
    }

    const workflowRunId = response.headers.get('x-workflow-run-id');
    if (!workflowRunId) {
      throw new Error(
        'Workflow run ID not found in "x-workflow-run-id" response header',
      );
    }

    // Notify the caller that the chat POST request was sent.
    // This is useful for tracking the chat history on the client
    // side and allows for inspecting response headers.
    await this.onChatSendMessage?.(response, options);

    // Flush the initial stream until the end or an error occurs
    try {
      const chunkStream = parseJsonEventStream({
        stream: response.body,
        schema: uiMessageChunkSchema,
      });
      for await (const chunk of createAsyncIterableStream(chunkStream)) {
        if (!chunk.success) {
          throw chunk.error;

View on GitHub (pinned to 69428b1f8b)

Solutions

  1. Ensure the server sets the 'x-workflow-run-id' response header on the chat POST response.
  2. Expose the header through proxies/CORS (e.g. Access-Control-Expose-Headers: x-workflow-run-id).
  3. Update the server workflow package so the header is emitted by the built-in handler.

Example fix

// server (before)
return new Response(stream);
// after
return new Response(stream, {
  headers: { 'x-workflow-run-id': workflowRun.id },
});
Defensive patterns

Strategy: validation

Validate before calling

const res = await fetch(chatUrl, { method: 'OPTIONS' });
if (!res.headers.get('access-control-expose-headers')?.includes('x-workflow-run-id')) {
  console.warn('Server/proxy must expose x-workflow-run-id header');
}

Type guard

function hasWorkflowRunId(headers: Headers): headers is Headers & { get(id: 'x-workflow-run-id'): string } {
  return headers.get('x-workflow-run-id') !== null;
}

Try / catch

try {
  await transport.sendMessages({ chatId, messages });
} catch (e) {
  if (e instanceof Error && e.message.includes('x-workflow-run-id')) {
    console.error('Server did not return workflow run id header — check server handler version and proxy header exposure');
  } else throw e;
}

Prevention

When it happens

Trigger: Server responds 200 but omits the 'x-workflow-run-id' header — e.g. a custom/proxy server implementation, middleware stripping headers, or an outdated server SDK version that doesn't set the header.

Common situations: Rolling your own chat endpoint instead of using the workflow server helper; reverse proxy or CORS middleware dropping custom headers; version mismatch between client transport and server package.

Related errors


AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30). Data as JSON: /api/errors/851674ff613decfb. Report an issue: GitHub.