{"record":{"id":"f343eb28478a06eb","repo":"mastra-ai/mastra","slug":"mode-not-found-modeid","errorCode":null,"errorMessage":"Mode not found: ${modeId}","messagePattern":"Mode not found: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/core/src/agent-controller/session.ts","lineNumber":1709,"sourceCode":"\n  /** Set the currently-selected mode id (on default resolution or hydration). */\n  set({ modeId }: { modeId: string }): void {\n    this.#id = modeId;\n  }\n\n  /**\n   * Switch to a different mode.\n   *\n   * Emits `mode_changed`, then runs the version-guarded sequence: remember the\n   * outgoing mode's model, persist the new mode, then resolve and apply the\n   * incoming mode's model — emitting `model_changed` once applied. A newer\n   * switch starting mid-flight supersedes this one, which then bails before\n   * emitting `model_changed`.\n   */\n  async switch({ modeId }: { modeId: string }): Promise<void> {\n    const mode = this.#resolveMode?.(modeId) ?? null;\n    if (!mode) {\n      throw new Error(`Mode not found: ${modeId}`);\n    }\n\n    const previousModeId = this.#id;\n    const previousModelId = this.#model.get();\n    const version = ++this.#switchVersion;\n    this.#id = modeId;\n\n    // Emit the mode change immediately so UIs can update without waiting for\n    // the storage round-trips below.\n    this.#bus.emit({ type: 'mode_changed', modeId, previousModeId });\n\n    // Remember the outgoing mode's model before moving on.\n    if (previousModelId) {\n      await this.#model.saveForMode({ modeId: previousModeId, modelId: previousModelId });\n    }\n    if (this.#switchVersion !== version) return;\n\n    await this.#store()?.set(MODE_ID_KEY, modeId);","sourceCodeStart":1691,"sourceCodeEnd":1727,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/agent-controller/session.ts#L1691-L1727","documentation":"ModeState.switch() validates the requested modeId against the host's mode catalog before changing state. If the catalog resolver returns no definition for that id, the switch is rejected up front so no partial switch (version bump, model change events) occurs.","triggerScenarios":"Calling switch({ modeId }) with a typo'd id, an id from another project's catalog, or a mode that was removed/renamed; programmatic switching based on stale persisted preferences.","commonSituations":"Custom modes registered conditionally (env-dependent) so the id is absent at runtime; renaming a built-in mode in an upgrade; user config referencing removed modes.","solutions":["Validate the id against the catalog before switching (resolve or list modes first).","Update the caller to a current mode id from the catalog's default.","Register the missing mode in the catalog, or migrate stale saved mode ids on load."],"exampleFix":"// before\nawait session.mode.switch({ modeId: 'build' }); // throws if 'build' no longer exists\n// after\nconst available = getCatalogModeIds();\nconst id = available.includes('build') ? 'build' : defaultModeId;\nawait session.mode.switch({ modeId: id });","handlingStrategy":"validation","validationCode":"const valid = !!resolveMode(modeId);\nif (!valid) throw new Error(`Unknown mode: ${modeId}; available: ${listModeIds().join(', ')}`);","typeGuard":null,"tryCatchPattern":"try {\n  await session.mode.switch({ modeId });\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('Mode not found: ')) {\n    await session.mode.switch({ modeId: defaultModeId });\n  } else throw e;\n}","preventionTips":["Populate mode pickers from the live catalog, not hardcoded ids","Validate user config mode ids at startup","Handle mode renames with an id-migration map","Log available mode ids in the error path for debugging"],"tags":["state","configuration","validation"],"backgroundTag":"mode-not-found","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}