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

Blocked ultragoal checkpoint Codex snapshot is missing objec

Error message

Blocked ultragoal checkpoint Codex snapshot is missing objective text.

What it means

The Codex snapshot supplied for a blocked checkpoint is available but contains no objective text. Objective matching is mandatory for blocked checkpoints, so an empty objective cannot be reconciled against the plan's expected/compatible objectives.

Source

Thrown at src/ultragoal/artifacts.ts:1819

      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: 'Codex get_goal was unavailable due to a DB/schema/context error; strict completion reconciliation is deferred until get_goal works.',
      });
      return plan;
    }
    if (!snapshot?.available) {
      throw new UltragoalError('Blocked ultragoal checkpoints require either a get_goal snapshot for the completed legacy Codex goal that blocked create_goal, an unavailable get_goal error JSON for a Codex DB/schema/context failure, or a matching native blocked snapshot; pass --codex-goal-json.');
    }
    if (!snapshot.objective) {
      throw new UltragoalError('Blocked ultragoal checkpoint Codex snapshot is missing objective text.');
    }
    const blockedSnapshotMatchesExpected = [expectedCodexObjective(plan, goal), ...compatibleCodexObjectives(plan)]
      .some((objective) => normalizeObjective(objective) === normalizeObjective(snapshot.objective ?? ''));
    if (snapshot.status === 'blocked') {
      if (!blockedSnapshotMatchesExpected) {
        throw new UltragoalError(
          `Blocked ultragoal checkpoint objective mismatch: expected one of [${[expectedCodexObjective(plan, goal), ...compatibleCodexObjectives(plan)].join(' | ')}], got ${snapshot.objective}. Matching native blocked checkpoints require the expected/compatible Codex objective; finish or clear the foreign goal, or pass a matching blocked get_goal snapshot with --evidence.`,
        );
      }
      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,

View on GitHub (pinned to 3ad79a8a6f)

Solutions

  1. Re-fetch the goal with get_goal and confirm the objective field is populated before recording the checkpoint
  2. If the upstream goal genuinely has no objective, that goal cannot be used as blocked-checkpoint evidence — fix the goal definition or use the db_schema_context_error deferral path
  3. Update snapshot fixtures to include objective text
Defensive patterns

Strategy: validation

Validate before calling

const snap = parseCodexGoalSnapshot(options.codexGoal);
if (snap?.available && !snap.objective) throw new Error('snapshot missing objective');

Type guard

const snapshotHasObjective = (s: any): s is { objective: string } => typeof s?.objective === 'string' && s.objective.length > 0;

Prevention

When it happens

Trigger: Passing --codex-goal-json whose parsed snapshot has available: true but objective is empty/undefined.

Common situations: get_goal returning a sparse object; hand-written snapshot fixtures that omit the objective field; API version changes dropping the objective field.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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