mastra-ai/mastra · error · Error

Failed to observe workflow stream: ${response.statusText}

Error message

Failed to observe workflow stream: ${response.statusText}

What it means

Thrown by Run.observe() (used by observeStream) when the POST to /workflows/:id/observe returns a non-OK HTTP status. Observation attaches to an existing run's event stream, so failure typically means the run cannot be observed on the server.

Source

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

   * for await (const event of stream) {
   *   console.log('Received:', event);
   * }
   * ```
   */
  async observe(params?: { offset?: number }): Promise<globalThis.ReadableStream<StreamVNextChunkType>> {
    const searchParams = new URLSearchParams();
    searchParams.set('runId', this.runId);
    if (params?.offset !== undefined) {
      searchParams.set('offset', String(params.offset));
    }

    const response: Response = await this.request(`/workflows/${this.workflowId}/observe?${searchParams.toString()}`, {
      method: 'POST',
      stream: true,
    });

    if (!response.ok) {
      throw new Error(`Failed to observe workflow stream: ${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());
  }

  /**
   * Observes workflow stream for a workflow run
   * @deprecated Use `observe()` instead for better control over replay position
   * @returns Promise containing the workflow execution results
   */
  async observeStream() {
    return this.observe();
  }

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Verify the run ID is active or recently completed and the workflowId matches.
  2. Check server logs for the HTTP error detail; statusText alone may be vague.
  3. Re-create/restart the run if its state was lost (e.g. after a dev server reload).
  4. Handle 404 by falling back to fetching run status via non-streaming endpoints.

Example fix

// before
const observed = await run.observeStream();

// after
try {
  const observed = await run.observeStream();
} catch (e) {
  console.error('Cannot observe run:', e.message);
  const status = await run.status(); // fallback to polling
}
Defensive patterns

Strategy: try-catch

Validate before calling

const runs = await client.getWorkflowRuns(workflowId);
if (!runs.runs.some(r => r.runId === runId)) throw new Error(`Run ${runId} not found on ${workflowId}`);

Type guard

function runExists(runs: { runs: { runId: string }[] }, runId: string): boolean {
  return runs.runs.some(r => r.runId === runId);
}

Try / catch

try {
  const stream = await run.observeStream();
} catch (e) {
  if (/Failed to observe/.test(e.message)) {
    console.error('Observation rejected:', e.message);
    const status = await run.status(); // polling fallback
  } else throw e;
}

Prevention

When it happens

Trigger: Calling run.observeStream() for a run ID that does not exist, has finished and been pruned, or when the server errors while setting up the observation stream (client-sdks/client-js/src/resources/run.ts:281).

Common situations: Observing a run after server restart lost in-memory state; wrong workflowId/runId; server 500 during stream setup.

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/0def71142e40f70a. Report an issue: GitHub.