Yeachan-Heo/oh-my-codex · error · Error
autoresearch candidate artifact candidate_commit must be str
Error message
autoresearch candidate artifact candidate_commit must be string|null
What it means
The optional candidate_commit field must be either null or a string. Numbers, booleans, objects, or arrays are rejected — candidate_commit represents the candidate git SHA and is null for noop/abort statuses.
Source
Thrown at src/autoresearch/runtime.ts:1036
}
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,
candidate_commit: record.candidate_commit,
base_commit: record.base_commit,
description: record.description,View on GitHub (pinned to 3ad79a8a6f)
Solutions
- Emit candidate_commit as the commit SHA string, or literal null when there is no candidate commit
- Do not wrap the SHA in an object; flatten it to a plain string
- Add a template example showing candidate_commit: null for noop/abort statuses
Example fix
// before
{"status":"noop","candidate_commit":0,"base_commit":"abc","description":"...","notes":[]}
// after
{"status":"noop","candidate_commit":null,"base_commit":"abc","description":"...","notes":[]} Defensive patterns
Strategy: type-guard
Validate before calling
const candidateCommit = parsed.candidate_commit ?? null;
if (candidateCommit !== null && typeof candidateCommit !== 'string') {
throw new Error('candidate_commit must be a commit SHA string or null');
} Type guard
function isCommitOrNull(v: unknown): v is string | null {
return v === null || typeof v === 'string';
} Try / catch
try { const a = parseAutoresearchCandidateArtifact(raw); }
catch (e) { if (e instanceof Error && e.message.includes('candidate_commit must be string|null')) { /* flatten the SHA to a plain string or null and retry */ } throw e; } Prevention
- Emit candidate_commit as a bare SHA string or literal null
- Show candidate_commit: null for noop/abort in template examples
- Validate field types in the worker harness before persisting
When it happens
Trigger: A worker emitting candidate_commit as a non-string (e.g. a number, or an object like {sha: '...'}), or an empty/undefined placeholder serialized as something other than null.
Common situations: Models wrapping the commit in an object, templates using a numeric placeholder (0) for 'no commit yet', or serialization libraries dropping null into undefined-based defaults.
Related errors
- autoresearch candidate artifact base_commit is required
- autoresearch candidate artifact must be valid JSON
- autoresearch candidate artifact must be a JSON object
- autoresearch candidate artifact status must be candidate|noo
- autoresearch candidate artifact description is required
AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27).
Data as JSON: /api/errors/95d7d3fc28ebb15f.
Report an issue: GitHub.