{"record":{"id":"1b696c6ea2623973","repo":"can1357/oh-my-pi","slug":"no-paused-goal","errorCode":null,"errorMessage":"No paused goal.","messagePattern":"No paused goal\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/goals/runtime.ts","lineNumber":422,"sourceCode":"\t\tvalidateTokenBudget(input.tokenBudget);\n\t\treturn await this.#withAccounting(async () => {\n\t\t\tconst existing = this.#host.getState();\n\t\t\tif (!existing?.enabled || !isAccountingStatus(existing.goal)) {\n\t\t\t\tthrow new Error(\"cannot replace goal because no goal is active\");\n\t\t\t}\n\t\t\tawait this.#flushUsageLocked(\"suppressed\");\n\t\t\tconst state = this.#createGoalState(objective, input.tokenBudget);\n\t\t\tthis.#budgetReportedFor = undefined;\n\t\t\tthis.#markActiveAccounting(state.goal);\n\t\t\tawait this.#commitState(state, { persist: \"goal\" });\n\t\t\treturn state;\n\t\t});\n\t}\n\n\tasync resumeGoal(): Promise<GoalModeState> {\n\t\treturn await this.#withAccounting(async () => {\n\t\t\tconst state = this.#getStateClone();\n\t\t\tif (!state?.goal) throw new Error(\"No paused goal.\");\n\t\t\tif (state.goal.status === \"complete\") throw new Error(\"Goal is already complete.\");\n\t\t\tstate.enabled = true;\n\t\t\tstate.mode = \"active\";\n\t\t\tstate.reason = undefined;\n\t\t\tstate.goal.status = \"active\";\n\t\t\tstate.goal.updatedAt = this.#now();\n\t\t\tthis.#budgetReportedFor = undefined;\n\t\t\tthis.#markActiveAccounting(state.goal);\n\t\t\tawait this.#commitState(state, { persist: \"goal\" });\n\t\t\treturn state;\n\t\t});\n\t}\n\n\tasync pauseGoal(): Promise<GoalModeState | undefined> {\n\t\treturn await this.#withAccounting(async () => {\n\t\t\tawait this.#flushUsageLocked(\"suppressed\");\n\t\t\tconst state = this.#getStateClone();\n\t\t\tif (!state?.goal) return undefined;","sourceCodeStart":404,"sourceCodeEnd":440,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/goals/runtime.ts#L404-L440","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nawait runtime.resumeGoal(); // throws if no goal\n// after\nconst state = host.getState();\nif (!state?.goal) {\n  await runtime.createGoal({ objective });\n} else {\n  await runtime.resumeGoal();\n}","handlingStrategy":"validation","validationCode":"const state = host.getState();\nif (!state?.goal) throw new Error('resumeGoal requires an existing goal');","typeGuard":"function hasGoal(state: { goal?: unknown } | undefined | null): boolean {\n  return !!state?.goal;\n}","tryCatchPattern":"try {\n  await runtime.resumeGoal();\n} catch (err) {\n  if (err instanceof Error && err.message === 'No paused goal.') {\n    await runtime.createGoal({ objective });\n  } else throw err;\n}","preventionTips":["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"],"tags":["state","goals"],"backgroundTag":"invalid-state-transition","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}