mastra-ai/mastra · error

Cannot build stream options without a current thread

Error message

Cannot build stream options without a current thread

What it means

Building stream options needs a currently selected thread on the Session. session.thread.getId() returned undefined, meaning no thread was set on the session, so the controller cannot snapshot thread context for the stream and throws.

Source

Thrown at packages/core/src/agent-controller/agent-controller.ts:1893

      const category = this.getToolCategory({ toolName });
      return !category || !deniedCategories.has(category);
    });
  }

  private async buildAgentMessageStreamOptions({
    session,
    requestContext: requestContextInput,
    tracingContext,
    tracingOptions,
  }: {
    session: Session<TState>;
    requestContext?: RequestContext;
    tracingContext?: TracingContext;
    tracingOptions?: TracingOptions;
  }): Promise<Record<string, unknown>> {
    const runThreadId = session.thread.getId();
    if (!runThreadId) {
      throw new Error('Cannot build stream options without a current thread');
    }

    session.run.clearAbortRequested();
    // Reconcile the in-memory model selection with the persisted per-mode model
    // before snapshotting it into the request context. In multiplayer
    // deployments another process (or a freshly-created Session for an existing
    // thread) may have persisted a different model; the per-instance cache would
    // otherwise run with a stale selection. No-op in the single-player TUI.
    await session.model.syncFromPersisted({ modeId: session.mode.get() });
    const requestContext = await this.buildRequestContext(session, requestContextInput);
    // Resolve mode-aware instructions at call time so the agent's own
    // instructions are never mutated by the harness.
    // When mode/harness instructions exist, combine them with the agent's
    // own instructions so dynamic instructions (e.g. AGENTS.md, project
    // context) aren't lost — the agent treats options.instructions as a
    // full override.
    let callTimeInstructions: string | undefined;
    if (this.config.agent) {

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Set a thread on the session first: session.thread.set({ threadId }) or create the session with overrides.threadId
  2. Create the session via a path that initializes a thread (e.g. with memory configured) before streaming
  3. Check upstream logic that may unset or never set the thread id

Example fix

// before
const session = await controller.createSessionForResource({}); // no thread
await controller.stream({ session });
// after
const session = await controller.createSessionForResource({ overrides: { threadId } });
await controller.stream({ session });
Defensive patterns

Strategy: validation

Validate before calling

if (!session.thread.getId()) throw new Error('Set a thread on the session before streaming');

Try / catch

try {
  return await controller.stream({ session });
} catch (e) {
  if (e instanceof Error && e.message.includes('without a current thread')) {
    session.thread.set({ threadId: await ensureThread(session) });
    return controller.stream({ session });
  }
  throw e;
}

Prevention

When it happens

Trigger: Invoking a run/stream-building API with a Session that was created without a thread (no overrides.threadId and no default thread created/set), typically a stateless session reused for a thread-scoped call.

Common situations: Reusing a session constructed in stateless mode for thread-scoped streaming; a createSession code path that skipped thread setup (e.g. thread lookup failed silently upstream); clearing the thread between calls.

Related errors


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