Yeachan-Heo/oh-my-codex · error · Error
autoresearch candidate artifact status must be candidate|noo
Error message
autoresearch candidate artifact status must be candidate|noop|abort|interrupted
What it means
The parsed artifact object's status field must be exactly one of 'candidate', 'noop', 'abort', or 'interrupted'. Any other value (including missing/undefined or a typo) is rejected.
Source
Thrown at src/autoresearch/runtime.ts:1033
worktreePath: manifest.worktree_path,
taskDescription: `autoresearch resume ${runId}`,
};
}
export function parseAutoresearchCandidateArtifact(raw: string): AutoresearchCandidateArtifact {
let parsed: unknown;
try {
parsed = JSON.parse(raw);
} catch {
throw new Error('autoresearch candidate artifact must be valid JSON');
}
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
throw new Error('autoresearch candidate artifact must be a JSON object');
}
const record = parsed as Record<string, unknown>;
const status = record.status;
if (status !== 'candidate' && status !== 'noop' && status !== 'abort' && status !== 'interrupted') {
throw new Error('autoresearch candidate artifact status must be candidate|noop|abort|interrupted');
}
if (record.candidate_commit !== null && typeof record.candidate_commit !== 'string') {
throw new Error('autoresearch candidate artifact candidate_commit must be string|null');
}
if (typeof record.base_commit !== 'string' || !record.base_commit.trim()) {
throw new Error('autoresearch candidate artifact base_commit is required');
}
if (typeof record.description !== 'string') {
throw new Error('autoresearch candidate artifact description is required');
}
if (!Array.isArray(record.notes) || record.notes.some((note) => typeof note !== 'string')) {
throw new Error('autoresearch candidate artifact notes must be a string array');
}
if (typeof record.created_at !== 'string' || !record.created_at.trim()) {
throw new Error('autoresearch candidate artifact created_at is required');
}
return {
status,View on GitHub (pinned to 3ad79a8a6f)
Solutions
- Set status to one of candidate|noop|abort|interrupted exactly (lowercase) in the artifact
- If a new status is genuinely needed, update the parser's allowed list and the worker template together
- Validate status in the worker harness before writing the artifact file
Example fix
// before
{"status":"done","base_commit":"abc","description":"...","notes":[]}
// after
{"status":"candidate","base_commit":"abc","description":"...","notes":[]} Defensive patterns
Strategy: validation
Validate before calling
const ALLOWED = new Set(['candidate', 'noop', 'abort', 'interrupted']);
const parsed = JSON.parse(raw) as Record<string, unknown>;
if (!ALLOWED.has(String(parsed.status))) {
throw new Error(`Invalid artifact status ${String(parsed.status)}; expected candidate|noop|abort|interrupted`);
} Type guard
function isCandidateStatus(v: unknown): v is 'candidate' | 'noop' | 'abort' | 'interrupted' {
return v === 'candidate' || v === 'noop' || v === 'abort' || v === 'interrupted';
} Try / catch
try { const a = parseAutoresearchCandidateArtifact(raw); }
catch (e) { if (e instanceof Error && e.message.includes('status must be candidate')) { /* normalize status casing/value and retry */ } throw e; } Prevention
- Enumerate the allowed statuses verbatim in the worker prompt/template
- Lowercase and trim status before writing the artifact
- Version-bump templates and parser together when adding new statuses
When it happens
Trigger: A worker writing status: 'success', 'done', 'Candidate' (case mismatch), or omitting status entirely in the candidate artifact JSON.
Common situations: Prompt/template drift where the worker invents a status name, version changes introducing a new status not yet supported, or case-sensitive mismatches from model output.
Related errors
- autoresearch candidate artifact must be valid JSON
- autoresearch candidate artifact must be a JSON object
- autoresearch candidate artifact candidate_commit must be str
- autoresearch candidate artifact base_commit is required
- autoresearch candidate artifact description is required
AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27).
Data as JSON: /api/errors/13e2926ec639510e.
Report an issue: GitHub.