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

Refusing to overwrite existing ${repoRelative(cwd, missionPa

Error message

Refusing to overwrite existing ${repoRelative(cwd, missionPath)}; pass --force to recreate it.

What it means

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.

Source

Thrown at src/autoresearch/goal.ts:144

}

async function appendLedger(cwd: string, slug: string, entry: AutoresearchGoalLedgerEntry): Promise<void> {
  await mkdir(autoresearchGoalDir(cwd, slug), { recursive: true });
  await appendFile(autoresearchGoalLedgerPath(cwd, slug), `${JSON.stringify(entry)}\n`, 'utf-8');
}

async function writeMission(cwd: string, mission: AutoresearchGoalMission): Promise<void> {
  await mkdir(autoresearchGoalDir(cwd, mission.slug), { recursive: true });
  await writeFile(autoresearchGoalMissionPath(cwd, mission.slug), `${JSON.stringify(mission, null, 2)}\n`, 'utf-8');
}

export async function createAutoresearchGoal(cwd: string, options: CreateAutoresearchGoalOptions): Promise<AutoresearchGoalMission> {
  const topic = requireText(options.topic, '--topic');
  const rubric = requireText(options.rubric, '--rubric');
  const slug = slugifyMissionName(options.slug ?? topic);
  const missionPath = autoresearchGoalMissionPath(cwd, slug);
  if (!options.force && existsSync(missionPath)) {
    throw new AutoresearchGoalError(`Refusing to overwrite existing ${repoRelative(cwd, missionPath)}; pass --force to recreate it.`);
  }

  const now = iso(options.now);
  const mission: AutoresearchGoalMission = {
    schema_version: 1,
    workflow: 'autoresearch-goal',
    slug,
    topic,
    rubric,
    ...(options.criticCommand?.trim() ? { critic_command: options.criticCommand.trim() } : {}),
    status: 'created',
    created_at: now,
    updated_at: now,
    mission_path: repoRelative(cwd, missionPath),
    rubric_path: repoRelative(cwd, autoresearchGoalRubricPath(cwd, slug)),
    ledger_path: repoRelative(cwd, autoresearchGoalLedgerPath(cwd, slug)),
    completion_path: repoRelative(cwd, autoresearchGoalCompletionPath(cwd, slug)),
  };

View on GitHub (pinned to 3ad79a8a6f)

Solutions

  1. Create resolvers fresh per operation batch rather than caching them long-term
  2. Disable respawn automation for worker panes
  3. On this error, re-resolve the worker pane (new split or fresh proof) and build a new pinned resolver with the new PID
  4. Invalidate all pinned PIDs on tmux server restart

Example fix

// before
const target = pinnedResolver(); // throws after pane churn

// after
let target;
try { target = pinnedResolver(); }
catch (err) {
  if (String(err.message).startsWith('tmux pane identity changed')) {
    const proof = readExactPaneProofSync(workerPaneId);
    if (proof.status === 'live') { /* re-pin with proof.pid and retry */ }
    else throw err;
  } else throw err;
}
Defensive patterns

Strategy: retry

Validate before calling

const proof = readExactPaneProofSync(workerPaneId); if (proof.status !== 'live' || proof.pid !== pinnedPid) planRepin();

Try / catch

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; } }

Prevention

When it happens

Trigger: 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.

Common situations: Long-lived resolvers kept across pane churn, respawn automation, tmux server restart invalidating pinned PIDs, or concurrent pane manipulation.

Related errors


AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27). Data as JSON: /api/errors/3263cb4ccec55b29. Report an issue: GitHub.