mastra-ai/mastra · error
No model available: this run started without a controller se
Error message
No model available: this run started without a controller session context, so no model selection could be resolved.
What it means
getDynamicModel throws this when the resolved modelId is missing AND the run has no agentControllerContext at all — the run started without session request context, so no model selection could ever have been made. The distinct message (vs 'No model selected') clarifies the user's /models choice was never the problem, e.g. a signal delivered to an idle thread.
Source
Thrown at mastracode/sdk/src/agents/model.ts:215
/**
* Dynamic model function that reads the current model from controller state.
* This allows runtime model switching via the /models picker.
*/
export function getDynamicModel(
{ requestContext }: { requestContext: RequestContext },
settingsPath?: string,
): ResolvedModel {
const agentControllerContext = requestContext.get('controller') as AgentControllerRequestContext<any> | undefined;
const modelId = agentControllerContext?.session?.modelId;
if (!modelId) {
// A missing controller context means the run was started without session
// request context at all (e.g. a signal delivered to an idle thread) —
// "use /models" would mislead there, the user's selection was never the
// problem.
if (!agentControllerContext) {
throw new Error(
'No model available: this run started without a controller session context, so no model selection could be resolved.',
);
}
throw new Error('No model selected. Use /models to select a model first.');
}
const thinkingLevel = resolveRequestThinkingLevel(agentControllerContext, settingsPath);
return resolveModel(modelId, { thinkingLevel, remapForCodexOAuth: true, requestContext });
}
/**
* Goal judge model resolver for the agent's `goal.judge` config. Resolves the
* configured goal judge model through mastracode's gateway so provider
* credentials (stored in auth storage, not just env) are injected — a bare model
* id handed to core's default model router would fail to find the API key.
*
* Returns `undefined` when no judge model is configured, which keeps the goalView on GitHub (pinned to 75dd419e61)
Solutions
- Start the run through a controller session so agentControllerContext is populated (open the thread / send an initiating request)
- Establish the session request context programmatically before invoking the agent
- Guard scheduled/signal-driven runs to skip model-requiring steps when no session context exists
- Configure a default model at the run level if you need headless runs without a session
Example fix
// before
await thread.signal('run-task'); // idle thread, no session context
// after
if (await thread.hasSessionContext()) {
await thread.signal('run-task');
} Defensive patterns
Strategy: validation
Validate before calling
if (!agentControllerContext) {
throw new Error('run requires a controller session; open a session first');
} Type guard
const hasControllerContext = (ctx: unknown): ctx is AgentControllerContext => Boolean(ctx);
Try / catch
try {
await runAgent(task);
} catch (err) {
if ((err as Error).message.includes('without a controller session context')) {
console.error('Start the run from an open session or establish request context first');
} else throw err;
} Prevention
- Only trigger model-requiring runs from sessions with established request context
- Guard signal/cron-driven code paths for missing session context
- Establish session context programmatically for headless runs
When it happens
Trigger: codeAgent → getDynamicModel finds `!modelId` and `!agentControllerContext` — the run began with no controller session context in request context (e.g. a signal/timer firing on an idle thread with no interactive session attached).
Common situations: Triggering a workflow/signal/cron on a thread that was never opened through the interactive session, running agents programmatically without establishing session request context, or replaying stored runs whose context is gone.
Related errors
- Project path is required
- ModelByInputTokens requires inputTokens for resolution
- Subconscious requires requestContext.organizationId to deriv
- Subconscious requires resourceId to derive scoped knowledge.
- Subconscious requires threadId to derive scoped knowledge.
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/96e129035d2324fe.
Report an issue: GitHub.