can1357/oh-my-pi · error · Error
No paused goal.
Error message
No paused goal.
What it means
resumeGoal re-enables a paused goal, but it throws when the cloned state contains no goal at all — there is nothing to resume. Only a paused (or otherwise non-complete) existing goal can be resumed.
Source
Thrown at packages/coding-agent/src/goals/runtime.ts:422
validateTokenBudget(input.tokenBudget);
return await this.#withAccounting(async () => {
const existing = this.#host.getState();
if (!existing?.enabled || !isAccountingStatus(existing.goal)) {
throw new Error("cannot replace goal because no goal is active");
}
await this.#flushUsageLocked("suppressed");
const state = this.#createGoalState(objective, input.tokenBudget);
this.#budgetReportedFor = undefined;
this.#markActiveAccounting(state.goal);
await this.#commitState(state, { persist: "goal" });
return state;
});
}
async resumeGoal(): Promise<GoalModeState> {
return await this.#withAccounting(async () => {
const state = this.#getStateClone();
if (!state?.goal) throw new Error("No paused goal.");
if (state.goal.status === "complete") throw new Error("Goal is already complete.");
state.enabled = true;
state.mode = "active";
state.reason = undefined;
state.goal.status = "active";
state.goal.updatedAt = this.#now();
this.#budgetReportedFor = undefined;
this.#markActiveAccounting(state.goal);
await this.#commitState(state, { persist: "goal" });
return state;
});
}
async pauseGoal(): Promise<GoalModeState | undefined> {
return await this.#withAccounting(async () => {
await this.#flushUsageLocked("suppressed");
const state = this.#getStateClone();
if (!state?.goal) return undefined;View on GitHub (pinned to 9690622007)
Solutions
- Create a goal first with createGoal before attempting to resume
- Check getState()?.goal exists before calling resumeGoal
- Only wire the resume action in the UI when a paused goal exists
Example fix
// before
await runtime.resumeGoal(); // throws if no goal
// after
const state = host.getState();
if (!state?.goal) {
await runtime.createGoal({ objective });
} else {
await runtime.resumeGoal();
} Defensive patterns
Strategy: validation
Validate before calling
const state = host.getState();
if (!state?.goal) throw new Error('resumeGoal requires an existing goal'); Type guard
function hasGoal(state: { goal?: unknown } | undefined | null): boolean {
return !!state?.goal;
} Try / catch
try {
await runtime.resumeGoal();
} catch (err) {
if (err instanceof Error && err.message === 'No paused goal.') {
await runtime.createGoal({ objective });
} else throw err;
} Prevention
- Only show a resume control when a goal exists in state
- After drops or clears, update UI affordances to 'create' rather than 'resume'
- Verify persisted goal state after session restarts before enabling resume
When it happens
Trigger: Calling resumeGoal on a session where no goal was ever created; calling it after the goal state was cleared/dropped; resuming on a fresh or restarted session without a persisted goal.
Common situations: Users pressing 'resume' with no goal set; scripts that unconditionally resume after a pause op that never ran; lost state after a restart without persistence.
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
- cannot create a new goal because this session already has a
- cannot replace goal because no goal is active
- Goal is already complete.
- cannot complete goal because no goal is active
- goal is already complete
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/1b696c6ea2623973.
Report an issue: GitHub.