can1357/oh-my-pi · error · ToolError
Plan mode is not active.
Error message
Plan mode is not active.
What it means
#handleAcpPlanProposal implements the plan-proposal tool used while ACP plan mode is active. It first checks session.getPlanModeState()?.enabled; if plan mode is not enabled it throws this ToolError. This guards the workflow contract: plan proposals are only meaningful (and only get auto-approval routing) when the session is actually in plan mode.
Source
Thrown at packages/coding-agent/src/modes/acp/acp-agent.ts:1884
}
/**
* Plan-proposal handler installed while ACP plan mode is active. The agent
* submits the finalized plan by writing its `<slug>`/title to
* `xd://propose`; this handler validates the plan file, normalizes the
* title, asks the ACP client to confirm (via `unstable_createElicitation`
* when supported), and on approval keeps the chosen plan path, exits plan
* mode, and notifies the client so the agent regains full tools.
*
* Mirrors `InteractiveMode.#handlePlanProposal` for the parts the agent sees
* (same `PlanApprovalDetails` shape). Clients without form-mode elicitation
* get an auto-approve so plan mode is never stranded — the agent always has
* a way out.
*/
async #handleAcpPlanProposal(session: AgentSession, title: string): Promise<AgentToolResult<unknown>> {
const state = session.getPlanModeState();
if (!state?.enabled) {
throw new ToolError("Plan mode is not active.");
}
const {
planFilePath,
planContent,
title: resolvedTitle,
} = await resolveApprovedPlan({
suppliedTitle: title,
statePlanFilePath: state.planFilePath,
readPlan: url => this.#readAcpPlanFile(session, url),
listPlanFiles: () => this.#listAcpLocalPlanFiles(session),
});
const approved = await this.#requestAcpPlanApprovalChoice(session.sessionId, resolvedTitle, planContent);
const details: PlanApprovalDetails = {
planFilePath,
title: resolvedTitle,
planExists: true,
};
if (!approved) {View on GitHub (pinned to 9690622007)
Solutions
- Enable plan mode on the session (setPlanModeState({ enabled: true, ... }) or an ACP mode change to ACP_PLAN_MODE_ID) before proposing a plan.
- Verify the session instance is the same one whose plan mode was enabled.
- Have the model/agent flow check plan-mode state before invoking the plan-proposal tool.
Example fix
// before
await proposePlan(session, title);
// after
session.setPlanModeState({ enabled: true, planFilePath: DEFAULT_PLAN_FILE_URL });
await proposePlan(session, title); Defensive patterns
Strategy: try-catch
Validate before calling
const state = session.getPlanModeState();
if (!state?.enabled) {
session.setPlanModeState({ enabled: true, planFilePath: DEFAULT_PLAN_FILE_URL });
}
await proposePlan(session, title); Type guard
function planModeActive(session: AgentSession): boolean {
return session.getPlanModeState()?.enabled === true;
} Try / catch
try {
await proposePlan(session, title);
} catch (err) {
if (err instanceof ToolError && err.message === "Plan mode is not active.") {
session.setPlanModeState({ enabled: true, planFilePath: DEFAULT_PLAN_FILE_URL });
await proposePlan(session, title);
} else throw err;
} Prevention
- Check plan-mode state before invoking plan-proposal tooling.
- Keep the enabled session and the session running the agent the same object.
- Persist/restore plan-mode state when resuming sessions.
When it happens
Trigger: Invoking the plan-proposal tool (or the agent reaching #handleAcpPlanProposal) while session.getPlanModeState() is null or { enabled: false } — e.g. the model calls the plan tool after plan mode was exited or never entered.
Common situations: A session was switched out of plan mode mid-run but the model still attempts the plan tool; a caller resumes a session whose plan-mode state was not persisted; the ACP client enabled plan mode on a different session object than the one running.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- No plan is awaiting approval — ${PROPOSE_DEVICE_PATH} only a
- directory stack is empty
- No messages to continue from
- Cannot continue from message role: assistant
- Cursor blob not found
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/32079a1be089c4a4.
Report an issue: GitHub.