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

autoresearch candidate artifact notes must be a string array

Error message

autoresearch candidate artifact notes must be a string array

What it means

parseAutoresearchCandidateArtifact validates the JSON candidate artifact written at the end of an autoresearch run. This error means the 'notes' field is either not an array or contains at least one element that is not a string. It exists because downstream consumers assume notes is a clean string[] for display and ledger recording.

Source

Thrown at src/autoresearch/runtime.ts:1045

  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,
    notes: record.notes,
    created_at: record.created_at,
  };
}

async function readCandidateArtifact(candidateFile: string): Promise<AutoresearchCandidateArtifact> {
  if (!existsSync(candidateFile)) {
    throw new Error(`autoresearch_candidate_missing:${candidateFile}`);
  }

View on GitHub (pinned to 3ad79a8a6f)

Solutions

  1. Inspect the artifact JSON and confirm notes is an array of strings only
  2. Fix the writer (or generator script) so it maps note objects to strings before serializing
  3. If the file was hand-edited, replace non-string entries with strings and re-run
  4. Upgrade/align the autoresearch runtime version that produced the artifact with the version parsing it

Example fix

// before
{"status":"candidate","notes":[{"text":"built"} ],...}

// after
{"status":"candidate","notes":["built"],...}
Defensive patterns

Strategy: validation

Validate before calling

const raw = JSON.parse(text);
if (!Array.isArray(raw.notes) || raw.notes.some((n) => typeof n !== 'string')) {
  raw.notes = raw.notes.map((n) => (typeof n === 'string' ? n : JSON.stringify(n)));
}

Type guard

function hasStringNotes(v: unknown): v is { notes: string[] } {
  return typeof v === 'object' && v !== null && Array.isArray((v as any).notes) && (v as any).notes.every((n: unknown) => typeof n === 'string');
}

Try / catch

try { parse(raw); } catch (e) { if ((e as Error).message.includes('notes must be a string array')) { /* normalize notes, retry */ } throw e; }

Prevention

When it happens

Trigger: Calling parseAutoresearchCandidateArtifact(raw) on a candidate artifact JSON whose 'notes' is missing, an object, or an array containing numbers/objects/null (e.g. {"notes": [1]} or {"notes": "did stuff"}).

Common situations: Hand-editing the candidate artifact file, a new version of the runner starting to write structured note objects instead of plain strings, or an external tool appending metadata into notes.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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