mastra-ai/mastra · error · HTTPException

agent controller "${controllerId}" not found

Error message

agent controller "${controllerId}" not found

What it means

getAgentControllerOrThrow resolves an agent controller via `mastra.getAgentController(controllerId)` and throws HTTP 404 when the mastra instance has no controller registered under that id (or when getAgentController itself is undefined on the instance). It is the shared guard used by all agent-controller HTTP handlers.

Source

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

} satisfies Record<ReservedThreadMetadataKey, true>;

function isReservedThreadMetadataKey(key: string): boolean {
  return Object.hasOwn(RESERVED_THREAD_METADATA_KEYS, key) || key.startsWith('modeModelId_');
}

/**
 * Resolves a controller by id via the canonical `mastra.getAgentController`
 * accessor, throwing a 404 if no controller is registered under that id.
 */
function getAgentControllerOrThrow(
  mastra: {
    getAgentController?: (id: string) => AgentController<any> | undefined;
  },
  controllerId: string,
): AgentController<any> {
  const controller = mastra.getAgentController?.(controllerId);
  if (!controller) {
    throw new HTTPException(404, { message: `agent controller "${controllerId}" not found` });
  }
  return controller;
}

async function getSession(
  controller: AgentController<any>,
  resourceId: string,
  options?: { tags?: Record<string, string>; scope?: string; threadId?: string },
  requestContext?: RequestContext,
): Promise<Session<any>> {
  await controller.init();
  const { tags, scope, threadId } = options ?? {};
  // Scoped sessions are independent sessions over the same resource (e.g. one
  // per git worktree), so qualify the stable session id with the scope to keep
  // their identities distinct as well. An exact thread binding doubles as the
  // stable session id when supplied.
  const id = threadId ?? (scope ? `${resourceId}::${scope}` : resourceId);
  return controller.createSession({ resourceId, id, ownerId: controller.id, tags, scope, threadId, requestContext });

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Fix the controllerId in the request to one registered on the running Mastra instance.
  2. Register the controller: configure `getAgentController` (and the controllers it returns) on your Mastra instance.
  3. List available controllers from your server config and have the client pick from that instead of hardcoding ids.
  4. Redeploy/restart so server code and client expectations reference the same controller set.

Example fix

// before
const c = await api.getAgentControllerSession({ controllerId: 'coders' });
// after
const c = await api.getAgentControllerSession({ controllerId: 'coder' }); // id registered via mastra.getAgentController
Defensive patterns

Strategy: validation

Validate before calling

const controllers = await api.listAgentControllers();
if (!controllers.some(c => c.id === controllerId)) {
  throw new Error(`Controller '${controllerId}' is not registered on this server`);
}

Type guard

function isKnownController(id: string, known: readonly string[]): id is string {
  return known.includes(id);
}

Try / catch

try {
  return await api.getControllerSession({ controllerId });
} catch (e) {
  if (isHttpError(e) && e.status === 404 && e.message.includes('agent controller')) {
    throw new Error(`Controller '${controllerId}' not found — check registration on the Mastra instance`);
  }
  throw e;
}

Prevention

When it happens

Trigger: Any agent-controller endpoint (sessions, threads, objectives, messages) called with a `controllerId` path/body parameter that was never registered on the Mastra instance, e.g. `mastra.getAgentController` not configured or the controller removed/renamed in code.

Common situations: Playground UI or client referencing a controller that exists in another deployment/environment; controller deleted during refactor; server restarted with an updated agent definition so previously valid ids 404; forgetting to register controllers when constructing Mastra.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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