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

Missing ${label}.

Error message

Missing ${label}.

What it means

A required string field on an ultragoal artifact is empty or whitespace-only. assertNonEmpty trims the value and throws with the field label (e.g. 'Missing architectureInvariantGate.evidence.') whenever it is undefined/blank.

Source

Thrown at src/ultragoal/artifacts.ts:1130

    total: plan.goals.length,
    pending: plan.goals.filter((goal) => goal.status === 'pending').length,
    inProgress: plan.goals.filter((goal) => goal.status === 'in_progress').length,
    complete: plan.goals.filter((goal) => goal.status === 'complete').length,
    failed: plan.goals.filter((goal) => goal.status === 'failed').length,
    reviewBlocked: activeReviewBlocked,
    historicalReviewBlocked: plan.goals.filter((goal) => goal.status === 'review_blocked').length - activeReviewBlocked,
    needsUserDecision: plan.goals.filter((goal) => goal.status === 'needs_user_decision').length,
    superseded: plan.goals.filter((goal) => goal.steeringStatus === 'superseded').length,
    steeringBlocked: plan.goals.filter((goal) => goal.steeringStatus === 'blocked').length,
    aggregateComplete: plan.aggregateCompletion?.status === 'complete',
    artifactComplete: isUltragoalDone(plan),
    activeGoalId: plan.activeGoalId,
  };
}

function assertNonEmpty(value: string | undefined, label: string): string {
  const trimmed = value?.trim();
  if (!trimmed) throw new UltragoalError(`Missing ${label}.`);
  return trimmed;
}

export function parseUltragoalSteeringDirective(raw: string): UltragoalSteeringProposal | null {
  const trimmed = raw.trim();
  if (!trimmed || trimmed.length < 5) return null;
  try {
    const parsed = JSON.parse(trimmed) as UltragoalSteeringProposal;
    if (!parsed || typeof parsed !== 'object') return null;
    if (!parsed.kind || typeof parsed.kind !== 'string') return null;
    if (!parsed.source || typeof parsed.source !== 'string') return null;
    if (!parsed.evidence || typeof parsed.evidence !== 'string') return null;
    if (!parsed.rationale || typeof parsed.rationale !== 'string') return null;
    if (!ULTRAGOAL_STEERING_MUTATION_KINDS.includes(parsed.kind as UltragoalSteeringMutationKind)) return null;
    if (!ULTRAGOAL_STEERING_SOURCES.includes(parsed.source as UltragoalSteeringSource)) return null;
    return parsed;
  } catch {
    return null;

View on GitHub (pinned to 3ad79a8a6f)

Solutions

  1. Find the field named in the message and populate it with a meaningful non-empty string
  2. Trim-check inputs before submission: skip optional empty entries from arrays rather than including ''
  3. If building gates programmatically, filter falsy values: arr.filter(s => s?.trim())
  4. Add a unit test that all required gate fields are non-empty before calling finalize

Example fix

// before
await finalize(cwd, { gate: { architectureInvariantGate: { status: 'passed', sourceArtifacts: [''], evidence: '' , invariants: [] } } });

// after
await finalize(cwd, { gate: { architectureInvariantGate: { status: 'passed', sourceArtifacts: ['docs/arch.md'], evidence: 'invariants verified', invariants: [] } } });
Defensive patterns

Strategy: validation

Validate before calling

const clean = (arr) => (arr ?? []).map(s => s?.trim()).filter(Boolean);
if (!evidence?.trim()) throw new Error('evidence required before finalize');

Type guard

function isNonEmptyString(v: unknown): v is string { return typeof v === 'string' && v.trim().length > 0; }

Prevention

When it happens

Trigger: Calling any validating writer (e.g. finalize/quality-gate submission) with a required string field — titles, evidence entries, sourceArtifacts entries — set to '', ' ', or undefined. Inside validateArchitectureInvariantGate it fires for each sourceArtifacts[] entry (label 'architectureInvariantGate.sourceArtifacts[]') and for invariantGate.evidence.

Common situations: Programmatically building a quality gate from optional data (empty strings instead of omitting fields); forms/templates that submit empty inputs; spreading partial objects with unset required fields.

Related errors


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