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 goal

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Start the run through a controller session so agentControllerContext is populated (open the thread / send an initiating request)
  2. Establish the session request context programmatically before invoking the agent
  3. Guard scheduled/signal-driven runs to skip model-requiring steps when no session context exists
  4. 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

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


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