mastra-ai/mastra · error · HTTPException

session has no active thread

Error message

session has no active thread

What it means

The set-objective handler resolves the controller and session, then reads the session's active thread id via `session.thread.getId()`. If the session has no active thread (null/undefined), it throws HTTP 400 because an objective cannot be attached without a thread.

Source

Thrown at packages/server/src/server/handlers/agent-controller.ts:1503

    'Sets a new objective for the session\u2019s thread. The agent\u2019s in-loop goal judge evaluates progress after each turn.',
  tags: ['AgentController', 'Goals'],
  requiresAuth: true,
  requiresPermission: 'agent-controller:execute',
  handler: async ({
    mastra,
    controllerId,
    resourceId,
    sessionScope,
    objective,
    judgeModelId,
    maxRuns,
    requestContext,
  }) => {
    try {
      const controller = getAgentControllerOrThrow(mastra, controllerId);
      const session = await getSession(controller, resourceId, { scope: sessionScope }, requestContext);
      const threadId = session.thread.getId();
      if (!threadId) throw new HTTPException(400, { message: 'session has no active thread' });
      const agent = getAgentForSession(controller, session);
      const record = await agent.setObjective(objective, {
        threadId,
        resourceId: session.identity.getResourceId(),
        ...(judgeModelId ? { judgeModelId } : {}),
        ...(maxRuns != null ? { maxRuns } : {}),
      });
      return { goal: record ?? undefined };
    } catch (error) {
      return handleError(error, 'error setting controller goal');
    }
  },
});

export const UPDATE_AGENT_CONTROLLER_GOAL_ROUTE = createRoute({
  method: 'PUT',
  path: '/agent-controller/:controllerId/sessions/:resourceId/goal',
  responseType: 'json' as const,

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Send at least one message (or explicitly create/activate a thread) before setting an objective.
  2. Use the session/thread creation endpoint to materialize a thread, then retry the objective call.
  3. Verify the controller's session factory is configured to create threads on session creation.
  4. Check server logs for earlier thread-creation failures (storage misconfig) that left the session threadless.

Example fix

// before
await api.setObjective({ controllerId, resourceId, objective }); // 400: no thread
// after
await api.sendMessage({ controllerId, resourceId, messages: [{ role: 'user', content: 'hi' }] });
await api.setObjective({ controllerId, resourceId, objective });
Defensive patterns

Strategy: try-catch

Validate before calling

const session = await api.getSession({ controllerId, resourceId });
if (!session.threadId) {
  await api.sendMessage({ controllerId, resourceId, messages: [{ role: 'user', content: 'start' }] });
}

Type guard

function hasActiveThread(s: { threadId?: string | null }): s is { threadId: string } {
  return typeof s.threadId === 'string' && s.threadId.length > 0;
}

Try / catch

try {
  await api.setObjective({ controllerId, resourceId, objective });
} catch (e) {
  if (isHttpError(e) && e.status === 400 && e.message.includes('no active thread')) {
    await api.sendMessage({ controllerId, resourceId, messages: [{ role: 'user', content: 'init' }] });
    await api.setObjective({ controllerId, resourceId, objective });
  } else throw e;
}

Prevention

When it happens

Trigger: Calling the set-objective endpoint against a session that was created without a thread or whose thread was never initialized/lazy-created; session constructed lazily so no thread exists until a first message is sent.

Common situations: Clients setting an objective immediately after creating a session before any message/thread materialization; thread deleted server-side while the session record persists; sessions in environments where thread creation is disabled or failed silently.

Related errors


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