mastra-ai/mastra · error · Error

resumeStream() on DurableAgent requires a runId in streamOpt

Error message

resumeStream() on DurableAgent requires a runId in streamOptions.

What it means

DurableAgent.resumeStream() overrides the base Agent signature and requires the target runId to be supplied as streamOptions.runId (it resumes a persisted durable run, not an implicit one). If streamOptions is missing or has no runId, this plain Error is thrown at durable-agent.ts:2551.

Source

Thrown at packages/core/src/agent/durable/durable-agent.ts:2551

      resourceId,
      cleanup,
      abort,
    };
  }

  /**
   * Override the inherited `resumeStream()` so that callers using the base
   * `Agent` API (including `approveToolCall` / `declineToolCall`) are routed
   * through the durable `resume()` path instead of the regular Agent's
   * snapshot-based resume.
   *
   * Returns just the `MastraModelOutput` (matching the base Agent's return
   * type) while internally delegating to `this.resume()`.
   */
  override async resumeStream(resumeData: any, streamOptions?: any): Promise<MastraModelOutput<TOutput>> {
    const runId = streamOptions?.runId;
    if (!runId) {
      throw new Error('resumeStream() on DurableAgent requires a runId in streamOptions.');
    }
    const { runId: _runId, ...resumeOptions } = streamOptions;
    const result = await this.resume(runId, resumeData, {
      ...resumeOptions,
      // Close the stream when the workflow re-suspends so the caller's
      // `for await` loop terminates. Without this the stream stays open
      // indefinitely when the resumed turn hits another suspend point.
      [CLOSE_ON_SUSPEND]: true,
    } as Parameters<DurableAgent<TAgentId, TTools, TOutput>['resume']>[2]);
    return result.output;
  }

  /**
   * Override the inherited `approveToolCall()` to route through the durable
   * `resume()` path.
   */
  override async approveToolCall(
    options: { runId: string; toolCallId?: string } & Record<string, any>,

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Pass the runId explicitly: agent.resumeStream(resumeData, { runId }).
  2. Reuse the runId captured from the original stream()/resume() result object.
  3. If migrating from the base Agent, update call sites — the durable variant requires the extra option.
  4. Use agent.resume(runId, data) if you need the full DurableAgentStreamResult rather than the stream output.

Example fix

// before
await agent.resumeStream({ approved: true });
// after
await agent.resumeStream({ approved: true }, { runId });
Defensive patterns

Strategy: validation

Validate before calling

if (!streamOptions?.runId) throw new Error('runId required for resumeStream');

Type guard

function hasRunId(o: unknown): o is { runId: string } {
  return typeof o === 'object' && o !== null && typeof (o as any).runId === 'string' && (o as any).runId.length > 0;
}

Try / catch

try {
  await agent.resumeStream(data, opts);
} catch (e) {
  if (String(e).includes('requires a runId in streamOptions')) {
    // recover runId from your persistence or fail fast with a clear client error
  } else throw e;
}

Prevention

When it happens

Trigger: Calling agent.resumeStream(data) with no second argument; passing options without runId; migrating from base Agent code where resumeStream never needed an explicit runId; destructuring mistakes that drop the runId field.

Common situations: Migrating code written against the base Agent (where resumeStream needs no explicit runId) to DurableAgent; dropping runId via careless destructuring of streamOptions; calling resumeStream directly from UI code that only holds resumeData.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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