{"record":{"id":"f5256a71275ea31b","repo":"Yeachan-Heo/oh-my-codex","slug":"autoresearch-active-run-exists","errorCode":"autoresearch_active_run_exists","errorMessage":"autoresearch_active_run_exists:${state.run_id}","messagePattern":"autoresearch_active_run_exists:(.+?)","errorType":"error_code","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/autoresearch/runtime.ts","lineNumber":291,"sourceCode":"\nasync function readJsonFile<T>(filePath: string): Promise<T> {\n  return JSON.parse(await readFile(filePath, 'utf-8')) as T;\n}\n\nasync function readActiveRunState(projectRoot: string): Promise<AutoresearchActiveRunState | null> {\n  const file = activeRunStateFile(projectRoot);\n  if (!existsSync(file)) return null;\n  return readJsonFile<AutoresearchActiveRunState>(file);\n}\n\nasync function writeActiveRunState(projectRoot: string, value: AutoresearchActiveRunState): Promise<void> {\n  await writeJsonFile(activeRunStateFile(projectRoot), value);\n}\n\nasync function assertAutoresearchLockAvailable(projectRoot: string): Promise<void> {\n  const state = await readActiveRunState(projectRoot);\n  if (state?.active && state.run_id) {\n    throw new Error(`autoresearch_active_run_exists:${state.run_id}`);\n  }\n}\n\nasync function activateAutoresearchRun(manifest: AutoresearchRunManifest): Promise<void> {\n  await writeActiveRunState(manifest.repo_root, {\n    schema_version: 1,\n    active: true,\n    run_id: manifest.run_id,\n    mission_slug: manifest.mission_slug,\n    repo_root: manifest.repo_root,\n    worktree_path: manifest.worktree_path,\n    status: manifest.status,\n    updated_at: nowIso(),\n  });\n}\n\nasync function deactivateAutoresearchRun(manifest: AutoresearchRunManifest): Promise<void> {\n  const previous = await readActiveRunState(manifest.repo_root);","sourceCodeStart":273,"sourceCodeEnd":309,"githubUrl":"https://github.com/Yeachan-Heo/oh-my-codex/blob/3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2/src/autoresearch/runtime.ts#L273-L309","documentation":"assertAutoresearchLockAvailable throws (code autoresearch_active_run_exists) when the active-run state file records an active run with a run_id. Autoresearch enforces a single active run per project root to prevent concurrent runs from corrupting shared worktrees and ledgers.","triggerScenarios":"Calling prepareAutoresearchRuntime or resumeAutoresearchRuntime while another run is already active — including a stale lock left behind by a crashed process that never finalized its run state.","commonSituations":"Running two autoresearch commands in parallel terminals, a previous run killed by SIGKILL/OOM without cleanup, CI retrying a job while the first is still active, or a stale .omx active-run state file after an interrupted session.","solutions":["Check if a run with that run_id is genuinely active (process list / CI logs); if so, wait for it or cancel it","If the previous run crashed, clear the active run state through the supported finalize/cancel command for the run_id in the message","Inspect the active-run state file under projectRoot/.omx and verify before manually clearing it","Avoid launching concurrent autoresearch runs against the same repo root; serialize them in your pipeline"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// before preparing/resuming, inspect the active-run state file\nimport { readFile } from 'node:fs/promises';\ntry {\n  const s = JSON.parse(await readFile(join(repoRoot, '.omx', 'active-run.json'), 'utf-8'));\n  if (s?.active && s.run_id) throw new Error(`Run ${s.run_id} still active`);\n} catch (e) { if ((e as NodeJS.ErrnoException).code !== 'ENOENT') throw e; }","typeGuard":"function isActiveRunState(v: unknown): v is { active: true; run_id: string } {\n  return typeof v === 'object' && v !== null && (v as any).active === true && typeof (v as any).run_id === 'string';\n}","tryCatchPattern":"try { await prepareAutoresearchRuntime(repoRoot, task); }\ncatch (e) { if (e instanceof Error && e.message.startsWith('autoresearch_active_run_exists')) { const id = e.message.split(':')[1]; /* cancel/finalize run id, then retry */ } throw e; }","preventionTips":["Serialize autoresearch runs per repo root (one at a time)","Always finalize or cancel runs, even on error paths (try/finally)","After crashes, clear active-run state via the supported recovery command before restarting"],"tags":["autoresearch","locking","concurrency","stale-state"],"backgroundTag":"concurrent-run-lock-held","analyzedSha":"3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2","analyzedAt":"2026-08-27T22:18:39.783Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}