{"record":{"id":"96664344f5ffd0ef","repo":"can1357/oh-my-pi","slug":"objective-is-required-when-op-replace","errorCode":null,"errorMessage":"objective is required when op=replace","messagePattern":"objective is required when op=replace","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/goals/runtime.ts","lineNumber":403,"sourceCode":"\t\tconst objective = input.objective.trim();\n\t\tif (!objective) throw new Error(\"objective is required when op=create\");\n\t\tvalidateTokenBudget(input.tokenBudget);\n\t\treturn await this.#withAccounting(async () => {\n\t\t\tconst existing = this.#host.getState();\n\t\t\tif (existing?.goal && existing.goal.status !== \"dropped\" && existing.goal.status !== \"complete\") {\n\t\t\t\tthrow new Error(\"cannot create a new goal because this session already has a goal\");\n\t\t\t}\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 replaceGoal(input: { objective: string; tokenBudget?: number }): Promise<GoalModeState> {\n\t\tconst objective = input.objective.trim();\n\t\tif (!objective) throw new Error(\"objective is required when op=replace\");\n\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();","sourceCodeStart":385,"sourceCodeEnd":421,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/goals/runtime.ts#L385-L421","documentation":"replaceGoal requires a non-empty objective string, mirroring createGoal. The runtime trims the input and throws when nothing remains, since replacing a goal with no objective would leave the tracker without a target.","triggerScenarios":"Calling replaceGoal with objective '' or whitespace-only; dropping the objective field when building tool arguments; upstream code joining an empty array into ''.","commonSituations":"Interactive goal-edit flows submitted with a blank field; LLM tool calls missing the objective argument; templates with unfilled placeholders.","solutions":["Supply a non-empty objective when calling replaceGoal","Validate/trim the objective in the caller before invoking the runtime","Reject blank objective at the input schema level"],"exampleFix":"// before\nawait runtime.replaceGoal({ objective: draft });\n// after\nconst objective = draft.trim();\nif (!objective) throw new Error('New goal objective must not be empty');\nawait runtime.replaceGoal({ objective });","handlingStrategy":"validation","validationCode":"if (typeof objective !== 'string' || objective.trim().length === 0) {\n  throw new Error('objective must be a non-empty string');\n}","typeGuard":"function hasObjective(input: { objective: string }): boolean {\n  return typeof input.objective === 'string' && input.objective.trim().length > 0;\n}","tryCatchPattern":"try {\n  await runtime.replaceGoal({ objective });\n} catch (err) {\n  if (err instanceof Error && err.message === 'objective is required when op=replace') {\n    return { ok: false, reason: 'empty-objective' };\n  }\n  throw err;\n}","preventionTips":["Validate edit-form input before submitting (non-empty after trim)","Apply the same objective validation helper used for createGoal","Require the objective field in your tool argument schema"],"tags":["validation","arguments","goals"],"backgroundTag":"missing-required-parameter","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}