mastra-ai/mastra · error · Error

Failed to stream workflow: ${response.statusText}

Error message

Failed to stream workflow: ${response.statusText}

What it means

Thrown by Run.stream() when the workflow streaming POST returns a non-OK HTTP status. The library surfaces the HTTP statusText because the response is not a usable event stream. The server-side reason is not included, so check the status code/statusText for the cause.

Source

Thrown at client-sdks/client-js/src/resources/run.ts:240

    searchParams.set('runId', this.runId);

    const requestContext = parseClientRequestContext(params.requestContext);
    const response: Response = await this.request(`/workflows/${this.workflowId}/stream?${searchParams.toString()}`, {
      method: 'POST',
      body: {
        inputData: params.inputData,
        initialState: params.initialState,
        requestContext,
        tracingOptions: params.tracingOptions,
        resourceId: params.resourceId,
        perStep: params.perStep,
        closeOnSuspend: params.closeOnSuspend,
      },
      stream: true,
    });

    if (!response.ok) {
      throw new Error(`Failed to stream workflow: ${response.statusText}`);
    }

    if (!response.body) {
      throw new Error('Response body is null');
    }

    // Pipe the response body through the transform stream
    return response.body.pipeThrough(this.createChunkTransformStream());
  }

  /**
   * Observe (reconnect to) an existing workflow stream.
   * Use this to resume receiving events after a disconnection.
   *
   * @param params.offset - Optional position to resume from (0-based). If omitted, replays all events.
   * @returns Promise containing a ReadableStream of workflow events
   *
   * @example

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Log the full HTTP response status; if needed use the non-streaming request path to get the error body.
  2. Verify the run ID and workflow ID are valid and the run is in a streamable state.
  3. Check Mastra server logs for the underlying 4xx/5xx cause.
  4. Retry transient 5xx failures with backoff.

Example fix

// before
const stream = await run.stream({ inputData });

// after
try {
  const stream = await run.stream({ inputData });
} catch (e) {
  console.error('Workflow stream failed:', e.message); // includes statusText
}
Defensive patterns

Strategy: try-catch

Validate before calling

const status = await run.status();
if (['success', 'failed'].includes(status.status)) throw new Error(`Run ${runId} not streamable (${status.status})`);

Type guard

function isStreamable(status: { status: string }): boolean {
  return ['pending', 'running', 'waiting', 'suspended'].includes(status.status);
}

Try / catch

try {
  const stream = await run.stream({ inputData });
} catch (e) {
  if (/Failed to stream workflow/.test(e.message)) {
    console.error('Stream rejected:', e.message);
    // check server logs / fall back to run.start()
  } else throw e;
}

Prevention

When it happens

Trigger: Calling run.stream() with params like closeOnSuspend where the server responds 4xx/5xx — e.g. unknown run ID, run already completed, or server error (client-sdks/client-js/src/resources/run.ts:240).

Common situations: Resuming a stale run ID after server restart; concurrent runs conflicting; server returning 500 due to workflow definition errors.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/4c9de7732acd20c8. Report an issue: GitHub.