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
- Set a thread on the session first: session.thread.set({ threadId }) or create the session with overrides.threadId
- Create the session via a path that initializes a thread (e.g. with memory configured) before streaming
- 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
- Always create thread-scoped sessions (overrides.threadId) for streaming calls
- Do not reuse stateless sessions for thread-scoped APIs
- Add a session invariant helper that asserts a thread exists before run/stream calls
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
- Thread not found: ${threadId}
- session has no active thread
- Invalid encrypted session data
- Invalid encrypted session data
- [MastraAuthGoogle] GOOGLE_COOKIE_PASSWORD is required for Go
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/7b9412a24df46bea.
Report an issue: GitHub.