can1357/oh-my-pi · error · ToolError
No pending action to apply — ${RESOLVE_DEVICE_PATH} is only
Error message
No pending action to apply — ${RESOLVE_DEVICE_PATH} is only valid while a staged preview is pending.${proposeHint} What it means
dispatchResolutionDevice handles the resolve device (apply/reject a staged preview). If action is apply/reject but there is no pending action — nothing was staged, or it was already applied/rejected — and there is nothing left to reject, it throws this ToolError; proposeHint suggests the propose device when plan mode is active.
Source
Thrown at packages/coding-agent/src/tools/resolve.ts:335
if (!invoker) {
session.clearPendingInvokers?.();
const proposeHint = session.peekPlanProposalHandler?.()
? ` To submit the plan for approval, write its title to ${PROPOSE_DEVICE_PATH} instead.`
: "";
// Rejecting is a request to reach the "no staged change" end-state, which
// already holds when nothing is pending — honor it as a successful
// cancellation instead of surfacing a hard error. Apply still errors.
if (action === "discard") {
const details: ResolveDetails = { action, reason: body };
return {
result: {
content: [{ type: "text", text: `Nothing to reject; no pending action remains.${proposeHint}` }],
details,
},
xdev: { ...xdevBase, inner: details },
};
}
throw new ToolError(
`No pending action to apply — ${RESOLVE_DEVICE_PATH} is only valid while a staged preview is pending.${proposeHint}`,
);
}
const invocation: ResolveInvocation = { action, reason: body };
const result = (await invoker(invocation)) as AgentToolResult<ResolveDetails>;
return { result, xdev: { ...xdevBase, inner: result.details } };
}
/** Streaming-safe call preview for a resolution-device write: `Resolve/Reject/Propose: <text>`. */
export function renderResolutionDeviceCall(device: ResolutionDeviceName, content: unknown, uiTheme: Theme): Component {
const body = typeof content === "string" ? replaceTabs(content.trim().split("\n")[0] ?? "") : "";
const title = device === PROPOSE_DEVICE_NAME ? "Propose" : device === REJECT_DEVICE_NAME ? "Reject" : "Resolve";
const text = renderStatusLine(
{
icon: "pending",
title,
description: body ? truncateToWidth(body, 72, Ellipsis.Omit) : undefined,
},View on GitHub (pinned to 9690622007)
Solutions
- Only call resolve after a tool staged a pending preview
- Re-run the staging step (plan/preview) before applying
- If plan mode is active, follow the proposeHint and use the propose device instead
Defensive patterns
Strategy: validation
Validate before calling
if (!hasPendingStagedAction()) { throw new Error("Nothing staged: run the plan/preview step before resolving"); } Try / catch
try { await resolveApply(); } catch (e) { if (e instanceof ToolError && e.message.includes("No pending action to apply")) { /* re-stage the action instead of retrying blindly */ } else throw e; } Prevention
- Call resolve exactly once per staged preview; guard against retry loops double-applying
- Check pending-state details after each resolve call
- Re-run staging after any session restart
When it happens
Trigger: Calling resolve with action=apply when no preview is pending; calling it twice (second call after the first consumed the staged action); reject when no action remains (the reject branch returns a friendly text for empty-pending, but apply throws).
Common situations: Double-apply race from an agent loop retry; session restarted losing the staged state; model invokes resolve before running a plan that stages an action.
Related errors
- Checkpoint already completed; continue from the retained rew
- 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
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/0202ec625c5aa0bc.
Report an issue: GitHub.