Yeachan-Heo/oh-my-codex · error · Error
autoresearch candidate artifact must be valid JSON
Error message
autoresearch candidate artifact must be valid JSON
What it means
parseAutoresearchCandidateArtifact JSON.parses the raw candidate artifact string and throws when parsing fails. The candidate artifact emitted by an autoresearch worker must be syntactically valid JSON before any field validation happens.
Source
Thrown at src/autoresearch/runtime.ts:1025
instructionsFile: manifest.instructions_file,
manifestFile: manifest.manifest_file,
ledgerFile: manifest.ledger_file,
latestEvaluatorFile: manifest.latest_evaluator_file,
resultsFile: manifest.results_file,
stateFile: activeRunStateFile(projectRoot),
candidateFile: manifest.candidate_file,
repoRoot: manifest.repo_root,
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');
}View on GitHub (pinned to 3ad79a8a6f)
Solutions
- Print/inspect the raw artifact string and find the JSON syntax error location
- Strip any surrounding markdown fences or prose so the string is pure JSON
- Ensure the artifact is fully flushed before reading it (write-then-rename or wait for worker exit)
- If the worker persistently emits non-JSON, fix the worker prompt/template to require raw JSON only
Example fix
// before const artifact = parseAutoresearchCandidateArtifact(rawLlmOutput); // raw contains ```json fences // after const json = rawLlmOutput.replace(/^```(?:json)?\n?/, '').replace(/\n?```$/, ''); const artifact = parseAutoresearchCandidateArtifact(json);
Defensive patterns
Strategy: type-guard
Validate before calling
function isParsableJson(s: string): boolean {
try { JSON.parse(s); return true; } catch { return false; }
}
if (!isParsableJson(raw)) throw new Error('Candidate artifact is not valid JSON; check worker output for fences/truncation.'); Type guard
function parseJsonSafe(s: string): unknown | undefined {
try { return JSON.parse(s); } catch { return undefined; }
} Try / catch
try { const a = parseAutoresearchCandidateArtifact(raw); }
catch (e) { if (e instanceof Error && e.message === 'autoresearch candidate artifact must be valid JSON') { /* strip fences, log raw excerpt, re-ask worker */ } throw e; } Prevention
- Have workers emit raw JSON only — no markdown fences or prose
- Write artifacts atomically (temp file + rename) so partial writes are never read
- Validate worker output with JSON.parse in the harness before persisting
When it happens
Trigger: Passing a candidate artifact string that is not parseable JSON: truncated output, markdown fences around JSON, an empty string, or a worker writing free-form text to the artifact file.
Common situations: LLM worker output with prose or code fences around the JSON, truncated stdout captured to a file, encoding issues/BOM, or a partially written artifact read while the worker was still writing it.
Related errors
- autoresearch candidate artifact must be a JSON object
- autoresearch candidate artifact notes must be a string array
- Invalid autoresearch-goal mission at ${repoRelative(cwd, pat
- autoresearch candidate artifact status must be candidate|noo
- autoresearch candidate artifact candidate_commit must be str
AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27).
Data as JSON: /api/errors/571cd5153cb62e0a.
Report an issue: GitHub.