{"record":{"id":"b429a4c549ab887e","repo":"Yeachan-Heo/oh-my-codex","slug":"cannot-record-a-blocked-checkpoint-for-goal-id","errorCode":null,"errorMessage":"Cannot record a blocked checkpoint for ${goal.id} while it is ${goal.status}; start or resume the ultragoal before recording a non-terminal blocker.","messagePattern":"Cannot record a blocked checkpoint for (.+?) while it is (.+?); start or resume the ultragoal before recording a non-terminal blocker\\.","errorType":"exception","errorClass":"UltragoalError","httpStatus":null,"severity":"error","filePath":"src/ultragoal/artifacts.ts","lineNumber":1795,"sourceCode":"  plan.updatedAt = now;\n  await writePlan(cwd, plan);\n  await appendLedger(cwd, { ts: now, event: 'goal_started', goalId: next.id, status: next.status, message: `Attempt ${next.attempt}` });\n  return { plan, goal: next, resumed: false, done: false };\n  });\n}\n\nexport async function checkpointUltragoal(cwd: string, options: CheckpointOptions): Promise<UltragoalPlan> {\n  return withUltragoalMutationLock(cwd, async () => {\n  const plan = await readUltragoalPlanUnderLock(cwd);\n  const goal = plan.goals.find((candidate) => candidate.id === options.goalId);\n  if (!goal) throw new UltragoalError(`Unknown ultragoal id: ${options.goalId}`);\n  if (plan.aggregateCompletion?.status === 'complete' && options.status !== 'complete') {\n    throw new UltragoalError(`Cannot record a ${options.status} checkpoint for ${goal.id} after the aggregate ultragoal plan is complete; the terminal aggregate receipt is immutable.`);\n  }\n  const now = iso(options.now);\n  if (options.status === 'blocked') {\n    if (goal.status !== 'in_progress') {\n      throw new UltragoalError(`Cannot record a blocked checkpoint for ${goal.id} while it is ${goal.status}; start or resume the ultragoal before recording a non-terminal blocker.`);\n    }\n    const snapshot = options.codexGoal === undefined ? null : parseCodexGoalSnapshot(options.codexGoal);\n    if (snapshot?.unavailableReason === 'db_schema_context_error') {\n      goal.updatedAt = now;\n      goal.failureReason = assertNonEmpty(options.evidence, '--evidence');\n      plan.activeGoalId = goal.id;\n      plan.updatedAt = now;\n      await writePlan(cwd, plan);\n      await appendLedger(cwd, {\n        ts: now,\n        event: 'goal_blocked',\n        goalId: goal.id,\n        status: goal.status,\n        evidence: options.evidence,\n        codexGoal: options.codexGoal,\n        message: 'Codex get_goal was unavailable due to a DB/schema/context error; strict completion reconciliation is deferred until get_goal works.',\n      });\n      return plan;","sourceCodeStart":1777,"sourceCodeEnd":1813,"githubUrl":"https://github.com/Yeachan-Heo/oh-my-codex/blob/3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2/src/ultragoal/artifacts.ts#L1777-L1813","documentation":"A 'blocked' checkpoint was requested for a goal whose status is not 'in_progress'. Non-terminal blockers may only be recorded against a goal that has been started or resumed; a pending/complete/failed goal cannot accept a blocked checkpoint.","triggerScenarios":"Calling checkpointUltragoal with status 'blocked' when goal.status is 'pending' (never started), 'complete', 'failed', or 'review_blocked'.","commonSituations":"Automation recording blockers before the start step ran; retrying a blocked report after the goal already failed or completed; out-of-order workflow steps.","solutions":["Start/resume the goal first (record an in_progress checkpoint), then record the blocked checkpoint","If the goal already reached a terminal state, record the appropriate terminal checkpoint instead of 'blocked'","Fix workflow ordering so 'start' always precedes 'blocked' reporting"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const goal = plan.goals.find(g => g.id === options.goalId);\nif (options.status === 'blocked' && goal.status !== 'in_progress') throw new Error('start the goal before blocking');","typeGuard":"const canBlock = (goal: UltragoalItem) => goal.status === 'in_progress';","tryCatchPattern":null,"preventionTips":["Enforce start-before-block ordering in orchestration","Check goal.status before choosing checkpoint status"],"tags":["ultragoal","checkpoint","blocked","state-machine"],"backgroundTag":"invalid-state-transition","analyzedSha":"3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2","analyzedAt":"2026-08-27T22:18:39.783Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}