can1357/oh-my-pi · error

Unsupported ACP mode: ${modeId}

Error message

Unsupported ACP mode: ${modeId}

What it means

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.

Source

Thrown at packages/coding-agent/src/modes/acp/acp-agent.ts:1847

		if (session.settings.get("plan.enabled")) {
			modes.push({
				id: ACP_PLAN_MODE_ID,
				name: "Plan",
				description: "Read-only planning mode that drafts a plan to a markdown file before any code changes",
			});
		}
		void session;
		return modes;
	}

	#getCurrentModeId(session: AgentSession): string {
		return session.getPlanModeState()?.enabled ? ACP_PLAN_MODE_ID : ACP_DEFAULT_MODE_ID;
	}

	#applyModeChange(session: AgentSession, modeId: string): void {
		const availableModes = this.#getAvailableModes(session);
		if (!availableModes.some(mode => mode.id === modeId)) {
			throw new Error(`Unsupported ACP mode: ${modeId}`);
		}
		if (modeId === ACP_PLAN_MODE_ID) {
			const previous = session.getPlanModeState();
			session.setPlanModeState({
				enabled: true,
				planFilePath: previous?.planFilePath ?? DEFAULT_PLAN_FILE_URL,
				workflow: previous?.workflow ?? "parallel",
				reentry: previous !== undefined,
			});
			// Mirror `InteractiveMode.#enterPlanMode`: register the plan-proposal
			// handler that consumes `xd://propose` writes from plan mode. Without
			// this, proposal dispatch falls through and plan mode has no approval
			// path (issue #1869).
			session.setPlanProposalHandler?.(title => this.#handleAcpPlanProposal(session, title));
		} else {
			session.setPlanProposalHandler?.(null);
			session.setPlanModeState(undefined);
		}

View on GitHub (pinned to 9690622007)

Solutions

  1. List the session's current modes (via the ACP modes/capabilities surface) and send only an id that appears there.
  2. Refresh the client's cached mode ids after (re)connecting so it matches ACP_DEFAULT_MODE_ID / ACP_PLAN_MODE_ID.
  3. If a new mode is needed, extend #getAvailableModes in acp-agent.ts rather than sending a custom id.

Example fix

// before
await session.setMode("code");
// after
const modes = await session.availableModes();
await session.setMode(modes.find(m => m.id === ACP_DEFAULT_MODE_ID).id);
Defensive patterns

Strategy: validation

Validate before calling

const modes = await getAvailableModes(session);
if (!modes.some(m => m.id === modeId)) throw new Error(`Mode ${modeId} not offered by session`);
await session.setMode(modeId);

Try / catch

try {
  await session.setMode(modeId);
} catch (err) {
  if (err.message.startsWith("Unsupported ACP mode")) {
    await session.setMode(ACP_DEFAULT_MODE_ID);
  } else throw err;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/be9e661b2c610c6a. Report an issue: GitHub.