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

autoresearch candidate artifact created_at is required

Error message

autoresearch candidate artifact created_at is required

What it means

The candidate artifact validator requires a 'created_at' timestamp as a non-empty string. This error fires when created_at is absent, not a string, or a whitespace-only string. It guarantees every candidate artifact carries a creation timestamp for ordering and audit.

Source

Thrown at src/autoresearch/runtime.ts:1048

  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}`);
  }
  return parseAutoresearchCandidateArtifact(await readFile(candidateFile, 'utf-8'));
}

View on GitHub (pinned to 3ad79a8a6f)

Solutions

  1. Open the candidate artifact and add created_at as an ISO 8601 string, e.g. new Date().toISOString()
  2. Fix the producer to always set created_at before writing the file
  3. If the file is truncated from an interrupted run, delete it and re-run the autoresearch session instead of patching

Example fix

// before
{"status":"candidate","created_at":1735689600000}

// after
{"status":"candidate","created_at":"2025-01-01T00:00:00.000Z"}
Defensive patterns

Strategy: validation

Validate before calling

const raw = JSON.parse(text);
if (typeof raw.created_at !== 'string' || !raw.created_at.trim()) {
  raw.created_at = new Date().toISOString(); // or reject upstream
}

Type guard

function hasCreatedAt(v: unknown): v is { created_at: string } {
  return typeof v === 'object' && v !== null && typeof (v as any).created_at === 'string' && (v as any).created_at.trim() !== '';
}

Prevention

When it happens

Trigger: parseAutoresearchCandidateArtifact on JSON where 'created_at' is missing, null, a number (epoch), or an empty/whitespace string.

Common situations: Generators writing epoch numbers instead of ISO strings, hand-authored artifacts omitting the field, or a truncated/interrupted run that wrote an incomplete file.

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/ed6e2dced13c677d. Report an issue: GitHub.