{"record":{"id":"be9e661b2c610c6a","repo":"can1357/oh-my-pi","slug":"unsupported-acp-mode-modeid","errorCode":null,"errorMessage":"Unsupported ACP mode: ${modeId}","messagePattern":"Unsupported ACP mode: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/modes/acp/acp-agent.ts","lineNumber":1847,"sourceCode":"\t\tif (session.settings.get(\"plan.enabled\")) {\n\t\t\tmodes.push({\n\t\t\t\tid: ACP_PLAN_MODE_ID,\n\t\t\t\tname: \"Plan\",\n\t\t\t\tdescription: \"Read-only planning mode that drafts a plan to a markdown file before any code changes\",\n\t\t\t});\n\t\t}\n\t\tvoid session;\n\t\treturn modes;\n\t}\n\n\t#getCurrentModeId(session: AgentSession): string {\n\t\treturn session.getPlanModeState()?.enabled ? ACP_PLAN_MODE_ID : ACP_DEFAULT_MODE_ID;\n\t}\n\n\t#applyModeChange(session: AgentSession, modeId: string): void {\n\t\tconst availableModes = this.#getAvailableModes(session);\n\t\tif (!availableModes.some(mode => mode.id === modeId)) {\n\t\t\tthrow new Error(`Unsupported ACP mode: ${modeId}`);\n\t\t}\n\t\tif (modeId === ACP_PLAN_MODE_ID) {\n\t\t\tconst previous = session.getPlanModeState();\n\t\t\tsession.setPlanModeState({\n\t\t\t\tenabled: true,\n\t\t\t\tplanFilePath: previous?.planFilePath ?? DEFAULT_PLAN_FILE_URL,\n\t\t\t\tworkflow: previous?.workflow ?? \"parallel\",\n\t\t\t\treentry: previous !== undefined,\n\t\t\t});\n\t\t\t// Mirror `InteractiveMode.#enterPlanMode`: register the plan-proposal\n\t\t\t// handler that consumes `xd://propose` writes from plan mode. Without\n\t\t\t// this, proposal dispatch falls through and plan mode has no approval\n\t\t\t// path (issue #1869).\n\t\t\tsession.setPlanProposalHandler?.(title => this.#handleAcpPlanProposal(session, title));\n\t\t} else {\n\t\t\tsession.setPlanProposalHandler?.(null);\n\t\t\tsession.setPlanModeState(undefined);\n\t\t}","sourceCodeStart":1829,"sourceCodeEnd":1865,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/modes/acp/acp-agent.ts#L1829-L1865","documentation":"AcpAgent.#applyModeChange validates the requested modeId against the modes advertised by #getAvailableModes for the session (currently default vs plan). Requesting any other id throws this error instead of silently ignoring the switch. This guarantees the client's mode selector never desyncs from what the session actually supports.","triggerScenarios":"Sending an ACP set-mode / mode-change request whose modeId is not in the session's availableModes list — e.g. a stale or client-invented mode id, or plan-mode id on a session where plan mode is not exposed.","commonSituations":"An editor extension caches mode ids from a previous session; a client hardcodes a mode id from a different tool's schema; the session's plan-mode support changed but the client kept sending the old plan mode id.","solutions":["List the session's current modes (via the ACP modes/capabilities surface) and send only an id that appears there.","Refresh the client's cached mode ids after (re)connecting so it matches ACP_DEFAULT_MODE_ID / ACP_PLAN_MODE_ID.","If a new mode is needed, extend #getAvailableModes in acp-agent.ts rather than sending a custom id."],"exampleFix":"// before\nawait session.setMode(\"code\");\n// after\nconst modes = await session.availableModes();\nawait session.setMode(modes.find(m => m.id === ACP_DEFAULT_MODE_ID).id);","handlingStrategy":"validation","validationCode":"const modes = await getAvailableModes(session);\nif (!modes.some(m => m.id === modeId)) throw new Error(`Mode ${modeId} not offered by session`);\nawait session.setMode(modeId);","typeGuard":null,"tryCatchPattern":"try {\n  await session.setMode(modeId);\n} catch (err) {\n  if (err.message.startsWith(\"Unsupported ACP mode\")) {\n    await session.setMode(ACP_DEFAULT_MODE_ID);\n  } else throw err;\n}","preventionTips":["Always fetch the session's advertised modes before switching; never cache ids across sessions.","Treat mode ids as opaque strings from the capabilities response.","Refresh mode lists after reconnects or session restores."],"tags":["acp","mode","validation"],"backgroundTag":"invalid-enum-value","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}