{"record":{"id":"3263cb4ccec55b29","repo":"Yeachan-Heo/oh-my-codex","slug":"refusing-to-overwrite-existing-reporelative-cwd","errorCode":null,"errorMessage":"Refusing to overwrite existing ${repoRelative(cwd, missionPath)}; pass --force to recreate it.","messagePattern":"Refusing to overwrite existing (.+?); pass --force to recreate it\\.","errorType":"validation","errorClass":"AutoresearchGoalError","httpStatus":null,"severity":"error","filePath":"src/autoresearch/goal.ts","lineNumber":144,"sourceCode":"}\n\nasync function appendLedger(cwd: string, slug: string, entry: AutoresearchGoalLedgerEntry): Promise<void> {\n  await mkdir(autoresearchGoalDir(cwd, slug), { recursive: true });\n  await appendFile(autoresearchGoalLedgerPath(cwd, slug), `${JSON.stringify(entry)}\\n`, 'utf-8');\n}\n\nasync function writeMission(cwd: string, mission: AutoresearchGoalMission): Promise<void> {\n  await mkdir(autoresearchGoalDir(cwd, mission.slug), { recursive: true });\n  await writeFile(autoresearchGoalMissionPath(cwd, mission.slug), `${JSON.stringify(mission, null, 2)}\\n`, 'utf-8');\n}\n\nexport async function createAutoresearchGoal(cwd: string, options: CreateAutoresearchGoalOptions): Promise<AutoresearchGoalMission> {\n  const topic = requireText(options.topic, '--topic');\n  const rubric = requireText(options.rubric, '--rubric');\n  const slug = slugifyMissionName(options.slug ?? topic);\n  const missionPath = autoresearchGoalMissionPath(cwd, slug);\n  if (!options.force && existsSync(missionPath)) {\n    throw new AutoresearchGoalError(`Refusing to overwrite existing ${repoRelative(cwd, missionPath)}; pass --force to recreate it.`);\n  }\n\n  const now = iso(options.now);\n  const mission: AutoresearchGoalMission = {\n    schema_version: 1,\n    workflow: 'autoresearch-goal',\n    slug,\n    topic,\n    rubric,\n    ...(options.criticCommand?.trim() ? { critic_command: options.criticCommand.trim() } : {}),\n    status: 'created',\n    created_at: now,\n    updated_at: now,\n    mission_path: repoRelative(cwd, missionPath),\n    rubric_path: repoRelative(cwd, autoresearchGoalRubricPath(cwd, slug)),\n    ledger_path: repoRelative(cwd, autoresearchGoalLedgerPath(cwd, slug)),\n    completion_path: repoRelative(cwd, autoresearchGoalCompletionPath(cwd, slug)),\n  };","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/Yeachan-Heo/oh-my-codex/blob/3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2/src/autoresearch/goal.ts#L126-L162","documentation":"Inside the pinned worker resolver, the pane is proven live but its PID differs from pinnedPid — the exact pane identity changed between when the resolver was pinned and when it was invoked. Rather than silently returning a target that now points at a different process, the resolver throws.","triggerScenarios":"Invoking a pinned resolver after the worker pane's process was replaced: respawn-pane, pane killed and recreated under the same id, or the worker crashing and the pane being reused.","commonSituations":"Long-lived resolvers kept across pane churn, respawn automation, tmux server restart invalidating pinned PIDs, or concurrent pane manipulation.","solutions":["Create resolvers fresh per operation batch rather than caching them long-term","Disable respawn automation for worker panes","On this error, re-resolve the worker pane (new split or fresh proof) and build a new pinned resolver with the new PID","Invalidate all pinned PIDs on tmux server restart"],"exampleFix":"// before\nconst target = pinnedResolver(); // throws after pane churn\n\n// after\nlet target;\ntry { target = pinnedResolver(); }\ncatch (err) {\n  if (String(err.message).startsWith('tmux pane identity changed')) {\n    const proof = readExactPaneProofSync(workerPaneId);\n    if (proof.status === 'live') { /* re-pin with proof.pid and retry */ }\n    else throw err;\n  } else throw err;\n}","handlingStrategy":"retry","validationCode":"const proof = readExactPaneProofSync(workerPaneId); if (proof.status !== 'live' || proof.pid !== pinnedPid) planRepin();","typeGuard":null,"tryCatchPattern":"catch (err) { if (/pane identity changed/.test(err.message)) { const p = readExactPaneProofSync(workerPaneId); if (p.status === 'live') { /* rebuild resolver with p.pid and retry */ } else throw err; } }","preventionTips":["Build resolvers per operation batch, not long-lived","Disable respawn on worker panes","Invalidate pinned PIDs on tmux server restart"],"tags":["tmux","pid-reuse","race-condition","worker"],"backgroundTag":"stale-pane-reference","analyzedSha":"3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2","analyzedAt":"2026-08-27T22:18:39.783Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}