Yeachan-Heo/oh-my-codex · error · UltragoalError

Cannot record final review blockers for ${goal.id} while it

Error message

Cannot record final review blockers for ${goal.id} while it is ${goal.status}; start or resume the ultragoal first.

What it means

recordFinalReviewBlockers requires the target goal to be in_progress. You cannot record final review blockers for a goal that is pending, complete, failed, or review_blocked — start or resume it first.

Source

Thrown at src/ultragoal/artifacts.ts:2090

      status: goal.status,
      evidence: options.evidence,
      codexGoal: options.codexGoal,
      qualityGate,
      message: 'Aggregate ultragoal plan completed with a clean final quality gate.',
    });
  }
  return plan;
  });
}

export async function recordFinalReviewBlockers(cwd: string, options: RecordFinalReviewBlockersOptions): Promise<{ plan: UltragoalPlan; blockedGoal: UltragoalItem; addedGoal: UltragoalItem }> {
  return withUltragoalMutationLock(cwd, async () => {
  const plan = await readUltragoalPlanUnderLock(cwd);
  const goal = plan.goals.find((candidate) => candidate.id === options.goalId);
  if (!goal) throw new UltragoalError(`Unknown ultragoal id: ${options.goalId}`);
  assertNonEmpty(options.evidence, '--evidence');
  if (goal.status !== 'in_progress') {
    throw new UltragoalError(`Cannot record final review blockers for ${goal.id} while it is ${goal.status}; start or resume the ultragoal first.`);
  }
  if (!isFinalRunCompletionCandidate(plan, goal)) {
    throw new UltragoalError(`Cannot record final review blockers for ${goal.id}; it is not the only unresolved ultragoal story.`);
  }

  const now = iso(options.now);
  const expectedObjective = expectedCodexObjective(plan, goal);
  const aggregateMode = codexGoalMode(plan) === 'aggregate';
  const reconciliation = reconcileCodexGoalSnapshot(
    options.codexGoal === undefined ? null : parseCodexGoalSnapshot(options.codexGoal),
    {
      expectedObjective,
      acceptedObjectives: aggregateMode ? compatibleCodexObjectives(plan) : undefined,
      allowedStatuses: ['active'],
      requireSnapshot: true,
      requireComplete: false,
    },
  );

View on GitHub (pinned to 3ad79a8a6f)

Solutions

  1. Record an in_progress checkpoint for the goal first, then call recordFinalReviewBlockers
  2. Guard against duplicate invocations in your orchestration
  3. If the goal is already review_blocked, no further blocker recording is needed for it
Defensive patterns

Strategy: validation

Validate before calling

if (goal.status !== 'in_progress') await checkpointUltragoal(cwd, { goalId, status: 'in_progress', evidence: 'start' });

Type guard

const isInProgress = (goal: UltragoalItem) => goal.status === 'in_progress';

Prevention

When it happens

Trigger: Calling recordFinalReviewBlockers when goal.status !== 'in_progress' (e.g. 'pending' never started, or already 'review_blocked').

Common situations: Calling the blocker-recording step before the start checkpoint; double-invoking the same blocker recording; retrying after the goal transitioned away.

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


AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27). Data as JSON: /api/errors/9407341276c17fb4. Report an issue: GitHub.