mastra-ai/mastra · error · HTTPException

Workflow run ${runId} already finished with status "${existi

Error message

Workflow run ${runId} already finished with status "${existingRun.status}". Use /observe to read its stream back, or stream a new runId.

What it means

Thrown when attempting to stream a workflow run whose `existingRun.status` is already in `TERMINAL_RUN_STATUSES` (e.g. completed, failed, canceled). The server returns HTTP 409 Conflict because a finished run cannot be streamed live. The message directs you to the /observe endpoint to replay the stored stream.

Source

Thrown at packages/server/src/server/handlers/workflows.ts:584

      if (!workflowId) {
        throw new HTTPException(400, { message: 'Workflow ID is required' });
      }

      if (!runId) {
        throw new HTTPException(400, { message: 'runId required to stream workflow' });
      }

      const { workflow } = await listWorkflowsFromSystem({ mastra, workflowId });

      if (!workflow) {
        throw new HTTPException(404, { message: 'Workflow not found' });
      }

      const existingRun = await workflow.getWorkflowRunById(runId, { withNestedWorkflows: false });

      if (existingRun && TERMINAL_RUN_STATUSES.includes(existingRun.status)) {
        throw new HTTPException(409, {
          message:
            `Workflow run ${runId} already finished with status "${existingRun.status}". ` +
            `Use /observe to read its stream back, or stream a new runId.`,
        });
      }

      const serverCache = mastra.getServerCache();

      const run = await workflow.createRun({ runId, resourceId: effectiveResourceId });
      const result = run.stream({ ...params, requestContext });

      if (serverCache) {
        return cacheRunStream({ cache: serverCache, runId, source: result.fullStream });
      }

      return result.fullStream;
    } catch (error) {
      return handleError(error, 'Error streaming workflow');

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Switch to the /observe endpoint to read the finished run's stream back instead of streaming live.
  2. Check the run status first (via getWorkflowRunById or the runs API) and only call stream for non-terminal statuses.
  3. Stream a new runId by starting a fresh run if you need live events again.

Example fix

// before
await workflow.stream({ runId }); // 409 if run finished
// after
const run = await workflow.getWorkflowRunById(runId);
if (TERMINAL_RUN_STATUSES.includes(run.status)) {
  await workflow.observeStream({ runId });
} else {
  await workflow.stream({ runId });
}
Defensive patterns

Strategy: try-catch

Validate before calling

const run = await workflow.getWorkflowRunById(runId);
const TERMINAL = ['completed', 'failed', 'canceled'];
if (run && TERMINAL.includes(run.status)) {
  // use observe/replay instead of stream
  await workflow.observeStream({ runId });
} else {
  await workflow.stream({ runId });
}

Type guard

const TERMINAL_RUN_STATUSES = ['completed', 'failed', 'canceled'] as const;
type RunStatus = 'running' | 'waiting' | ... | typeof TERMINAL_RUN_STATUSES[number];
function isTerminal(status: RunStatus): boolean {
  return (TERMINAL_RUN_STATUSES as readonly string[]).includes(status);
}

Try / catch

try {
  await workflow.stream({ runId });
} catch (e) {
  if (e instanceof MastraClientError && e.status === 409) {
    await workflow.observeStream({ runId }); // replay finished stream
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling the stream endpoint with a runId whose run already reached a terminal status; retrying a stream subscription after the run finished; resubscribing to a completed run after a page reload.

Common situations: UI reconnect logic blindly re-streams a runId after network loss when the run has since finished; polling loops that keep calling stream instead of switching to observe once the run ends; test scripts that re-run the same stream request.

Related errors


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