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

Cannot record a blocked ultragoal checkpoint while the exist

Error message

Cannot record a blocked ultragoal checkpoint while the existing Codex goal is ${snapshot.status ?? 'unknown'}; strict objective mismatch protection remains required for active or incomplete goals.

What it means

For a blocked checkpoint, the supplied Codex snapshot's status is neither 'blocked' nor 'complete' (or is unknown). Blocked checkpoints against an active/incomplete Codex goal are disallowed because strict objective-mismatch protection still applies to unfinished goals.

Source

Thrown at src/ultragoal/artifacts.ts:1846

      }
      const evidence = assertNonEmpty(options.evidence, '--evidence');
      goal.updatedAt = now;
      plan.activeGoalId = goal.id;
      plan.updatedAt = now;
      await writePlan(cwd, plan);
      await appendLedger(cwd, {
        ts: now,
        event: 'goal_blocked',
        goalId: goal.id,
        status: goal.status,
        evidence,
        codexGoal: options.codexGoal,
        message: 'Native Codex goal status is blocked for the matching objective; recorded a non-terminal goal_blocked checkpoint. Continue work without treating this as complete or failed; re-check get_goal when the blocker clears.',
      });
      return plan;
    }
    if (snapshot.status !== 'complete') {
      throw new UltragoalError(`Cannot record a blocked ultragoal checkpoint while the existing Codex goal is ${snapshot.status ?? 'unknown'}; strict objective mismatch protection remains required for active or incomplete goals.`);
    }
    const safeCompletedAggregateBlocker = isSafeCompletedAggregateBlockerSnapshot(plan, goal, snapshot, options.evidence);
    if (!safeCompletedAggregateBlocker && blockedSnapshotMatchesExpected) {
      throw new UltragoalError('Blocked ultragoal checkpoint is only for a different completed legacy Codex goal unless an aggregate Codex goal is already complete and unreconcilable while the active repo-native microgoal remains in progress.');
    }
    goal.updatedAt = now;
    if (safeCompletedAggregateBlocker) goal.failureReason = assertNonEmpty(options.evidence, '--evidence');
    plan.activeGoalId = goal.id;
    plan.updatedAt = now;
    await writePlan(cwd, plan);
    await appendLedger(cwd, {
      ts: now,
      event: 'goal_blocked',
      goalId: goal.id,
      status: goal.status,
      evidence: options.evidence,
      codexGoal: options.codexGoal,
      message: safeCompletedAggregateBlocker

View on GitHub (pinned to 3ad79a8a6f)

Solutions

  1. Wait for the Codex goal to reach 'blocked' or 'complete' and re-fetch the snapshot before recording
  2. If the goal is genuinely still running, don't record a blocked checkpoint yet — poll get_goal
  3. Handle new Codex statuses by mapping them to the closest supported status in your snapshot adapter
Defensive patterns

Strategy: validation

Validate before calling

if (snap.status !== 'blocked' && snap.status !== 'complete') { await waitForCodexGoalSettlement(); }

Type guard

const isSettledStatus = (s: unknown): s is 'blocked' | 'complete' => s === 'blocked' || s === 'complete';

Prevention

When it happens

Trigger: Passing a snapshot with status 'active', 'in_progress', or any value other than 'blocked'/'complete' when recording a blocked checkpoint (the 'blocked' native path at 1206 and 'complete' path at 1207-1208 are the only allowed statuses).

Common situations: Recording 'blocked' while the Codex goal is still actively running; get_goal returning a new intermediate status after a Codex version update; racing between Codex state changes and the checkpoint call.

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/32020d57ff69c6a6. Report an issue: GitHub.