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
- Find the field named in the message and populate it with a meaningful non-empty string
- Trim-check inputs before submission: skip optional empty entries from arrays rather than including ''
- If building gates programmatically, filter falsy values: arr.filter(s => s?.trim())
- 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
- Trim and filter every user-supplied string before building gate payloads
- Drop empty optional array entries instead of submitting ''
- Fail fast on blank required fields in your own form/UI layer
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
- agent name must not be empty
- `target` is required
- ${name} must be non-empty
- answers[${entry.index}].answer.other_text must be a non-empt
- team_worktree_worker_name_required
AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27).
Data as JSON: /api/errors/086a3036e283f3c4.
Report an issue: GitHub.