Yeachan-Heo/oh-my-codex · error · AutoresearchGoalError
Autoresearch goal ${mission.slug} is already complete; creat
Error message
Autoresearch goal ${mission.slug} is already complete; create a new goal or explicitly reopen via a future workflow before recording more verdicts. What it means
recordAutoresearchGoalVerdict refuses to record new verdicts once the mission's status is 'complete'. This is a terminal-state guard: a completed goal is immutable by design, and further verdicts require a new goal or an explicit future reopen workflow.
Source
Thrown at src/autoresearch/goal.ts:201
throw new AutoresearchGoalError(`Invalid autoresearch-goal mission at ${repoRelative(cwd, path)}.`);
}
return parsed;
}
export async function readAutoresearchGoalCompletion(cwd: string, slug: string): Promise<AutoresearchGoalCompletion | null> {
const path = autoresearchGoalCompletionPath(cwd, slugifyMissionName(slug));
if (!existsSync(path)) return null;
const parsed = JSON.parse(await readFile(path, 'utf-8')) as AutoresearchGoalCompletion;
return parsed;
}
export async function recordAutoresearchGoalVerdict(
cwd: string,
options: RecordAutoresearchGoalVerdictOptions,
): Promise<{ mission: AutoresearchGoalMission; completion: AutoresearchGoalCompletion }> {
const mission = await readAutoresearchGoal(cwd, options.slug);
if (mission.status === 'complete') {
throw new AutoresearchGoalError(`Autoresearch goal ${mission.slug} is already complete; create a new goal or explicitly reopen via a future workflow before recording more verdicts.`);
}
const evidence = requireText(options.evidence, '--evidence');
const now = iso(options.now);
const completion: AutoresearchGoalCompletion = {
schema_version: 1,
slug: mission.slug,
verdict: options.verdict,
passed: options.verdict === 'pass',
summary: options.summary?.trim() || evidence,
evidence,
...(options.artifactPath?.trim() ? { artifact_path: options.artifactPath.trim() } : {}),
...(mission.critic_command ? { critic_command: mission.critic_command } : {}),
recorded_at: now,
};
mission.status = options.verdict === 'pass' ? 'passed' : options.verdict === 'fail' ? 'failed' : 'blocked';
mission.updated_at = now;
await writeMission(cwd, mission);View on GitHub (pinned to 3ad79a8a6f)
Solutions
- Check mission.status before recording and branch your automation to stop or start a new goal
- Create a new autoresearch goal with `omx autoresearch-goal create` if more verdicts are genuinely needed
- If the completion was premature, manually revert status in the mission file only if no supported reopen workflow exists and you accept the risk
- Make your recording step idempotent by first reading the mission and skipping when complete
Example fix
// before
await recordAutoresearchGoalVerdict(repoRoot, { slug, evidence }); // throws if status === 'complete'
// after
const mission = await readAutoresearchGoal(repoRoot, slug);
if (mission.status !== 'complete') {
await recordAutoresearchGoalVerdict(repoRoot, { slug, evidence });
} Defensive patterns
Strategy: validation
Validate before calling
const mission = await readAutoresearchGoal(cwd, slug);
if (mission.status === 'complete') {
console.log('goal already complete; skipping verdict recording');
process.exit(0);
} Type guard
function isMissionComplete(m: { status?: string }): boolean {
return m.status === 'complete';
} Try / catch
try {
await recordAutoresearchGoalVerdict(cwd, options);
} catch (e) {
if (e instanceof AutoresearchGoalError && e.message.includes('already complete')) return; // idempotent skip
throw e;
} Prevention
- Read mission status before recording verdicts and branch automation accordingly
- Start a new goal when further work is needed after completion
- Make CI verdict steps idempotent by treating 'already complete' as success
When it happens
Trigger: Calling recordAutoresearchGoalVerdict(cwd, { slug, ... }) for a mission whose JSON has status === 'complete' — typically after completeAutoresearchGoal already succeeded or the status was set manually.
Common situations: Pipelines that keep iterating after a goal completes, re-running an automation step that records verdicts, or scripts that do not check mission status before recording.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- autoresearch_resume_terminal_run
- No autoresearch-goal mission found at ${repoRelative(cwd, pa
- Autoresearch goal ${mission.slug} cannot complete until prof
- Invalid autoresearch-goal mission at ${repoRelative(cwd, pat
- formatCodexGoalReconciliation(reconciliation)
AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27).
Data as JSON: /api/errors/7761cdbfc24f33e4.
Report an issue: GitHub.