Yeachan-Heo/oh-my-codex · error · MissionCommandError
Mission execution requires a task runner; use --dry-run for
Error message
Mission execution requires a task runner; use --dry-run for parser/plan validation.
What it means
During a real (non-dry-run) mission run, options.runTask is undefined. Actually-executing runs need a caller-supplied task runner; --dry-run paths return earlier without one.
Source
Thrown at src/cli/mission.ts:472
if (parsed.dryRun) {
for (const task of summary.tasks) task.status = "planned";
summary.counts = missionCounts(summary.tasks);
summary.completed_at = now().toISOString();
await persistSummary(paths.summaryPath, summary);
await appendLedger(paths.ledgerPath, { event: "mission_planned", at: summary.completed_at, slug: paths.slug, total: tasks.length, summary_path: paths.summaryPath });
if (parsed.json) stdout(JSON.stringify({ ok: true, summary_path: paths.summaryPath, ledger_path: paths.ledgerPath, summary }, null, 2));
else {
stdout(`mission planned: ${paths.slug} (${tasks.length} tasks)`);
for (const task of summary.tasks) stdout(`[planned] ${task.id} line ${task.source_line}: ${task.prompt}`);
stdout(`summary: ${paths.summaryPath}`);
stdout(`ledger: ${paths.ledgerPath}`);
}
return;
}
const runTask = options.runTask;
if (!runTask) throw new MissionCommandError("Mission execution requires a task runner; use --dry-run for parser/plan validation.");
await persistSummary(paths.summaryPath, summary);
await appendLedger(paths.ledgerPath, { event: "mission_started", at: startedAt, slug: paths.slug, total: tasks.length, summary_path: paths.summaryPath });
await runSelectedTasks(summary, paths, parsed, now, stdout, runTask, () => true);
summary.status = missionStatus(summary.tasks);
summary.completed_at = now().toISOString();
summary.counts = missionCounts(summary.tasks);
await persistSummary(paths.summaryPath, summary);
await appendLedger(paths.ledgerPath, { event: "mission_completed", at: summary.completed_at, slug: paths.slug, status: summary.status, counts: summary.counts });
if (parsed.json) stdout(JSON.stringify({ ok: summary.status === "passed", summary_path: paths.summaryPath, ledger_path: paths.ledgerPath, summary }, null, 2));
else {
stdout(`mission ${summary.status}: ${paths.slug}`);
stdout(`summary: ${paths.summaryPath}`);
stdout(`ledger: ${paths.ledgerPath}`);
}
if (summary.status === "failed") process.exitCode = 1;View on GitHub (pinned to 3ad79a8a6f)
Solutions
- Provide options.runTask when invoking run/resume/rerun programmatically
- Add --dry-run if you only need parser/plan validation
- Delegate to the actual CLI entrypoint which supplies the default runner
Example fix
// before
await missionCommand(['run', 'mission.md'], { stdout });
// after
await missionCommand(['run', 'mission.md'], { stdout, runTask: runCodexTask }); Defensive patterns
Strategy: validation
Validate before calling
if (action === 'run' && !parsed.dryRun && typeof options.runTask !== 'function') failEarly('runner required'); Type guard
const hasRunner = (o: MissionOptions): o is MissionOptions & { runTask: RunTask } =>
typeof o.runTask === 'function'; Prevention
- Default wrappers to --dry-run when no runner is configured
When it happens
Trigger: Calling missionCommand(['run', file], {}) without runTask and without --dry-run — the run reaches the execution stage and has no way to execute tasks.
Common situations: Host applications embedding the CLI without wiring the runner; tests that omit the runner stub; refactors dropping the option.
Related errors
- Mission execution requires a task runner; use status for rea
- No autoresearch-goal mission found at ${repoRelative(cwd, pa
- Missing value for ${flag}.
- --dry-run is only supported for mission run/plan.
- --continue-on-error is not supported for mission status.
AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27).
Data as JSON: /api/errors/32fb87b1784a2471.
Report an issue: GitHub.