Yeachan-Heo/oh-my-codex · critical · Error

shutdown_shared_session_HUD_pane_identity_changed:${config.h

Error message

shutdown_shared_session_HUD_pane_identity_changed:${config.hud_pane_id}

What it means

Identity check for the HUD pane in shared-session shutdown: the persisted hud_pane_id is live in tmux but its current PID differs from the recorded hud_pane_pid. The pane ID was reused by a different process, so the runtime refuses to kill it to avoid terminating an unrelated pane.

Source

Thrown at src/team/runtime.ts:5005

    // Explicit force means teardown now. Do not spend the graceful ack window
    // waiting for interactive panes or prompt workers that will be killed below.
    skipWorkerAcks = true;
  } else {
    skipWorkerAcks = useCleanFastPath;
  }

  const sessionName = config.tmux_session;
  const sharedSessionTopology = config.worker_launch_mode === 'interactive' && sessionName.includes(':')
    ? resolveSharedSessionShutdownTopology(sessionName, config.leader_pane_id, sanitized)
    : null;
  if (sharedSessionTopology?.status === 'unavailable') {
    throw new Error(`shutdown_shared_session_topology_unavailable:${sharedSessionTopology.detail}`);
  }
  if (typeof config.hud_pane_id === 'string' && /^%[0-9]+$/.test(config.hud_pane_id)
    && typeof config.hud_pane_pid === 'number' && Number.isSafeInteger(config.hud_pane_pid) && config.hud_pane_pid > 0) {
    const persistedHudProof = readExactPaneProofSync(config.hud_pane_id);
    if (persistedHudProof.status === 'live' && persistedHudProof.pid !== config.hud_pane_pid) {
      throw new Error(`shutdown_shared_session_HUD_pane_identity_changed:${config.hud_pane_id}`);
    }
  }
  const dispatchPolicy = resolveDispatchPolicy(manifest?.policy, config.worker_launch_mode);
  const shutdownRequestTimes = new Map<string, string>();

  if (!skipWorkerAcks) {
    // 1. Send shutdown inbox to each worker
    for (const w of config.workers) {
      try {
        const requestedAt = new Date().toISOString();
        await writeShutdownRequest(sanitized, w.name, 'leader-fixed', cwd);
        shutdownRequestTimes.set(w.name, requestedAt);
        const triggerDirective = buildTriggerDirective(
          w.name,
          sanitized,
          resolveInstructionStateRoot(w.worktree_path),
        );
        await dispatchCriticalInboxInstruction({

View on GitHub (pinned to 3ad79a8a6f)

Solutions

  1. Verify which process now owns the pane (tmux list-panes with pane_pid) and update or clear hud_pane_id/hud_pane_pid in team config
  2. Kill the stale HUD pane manually if you confirm it is safe, then retry shutdown
  3. Recreate the team if the config/state divergence is too large

Example fix

# before
omx team shutdown myteam

# after
tmux list-panes -t myteam -F '#{pane_id} #{pane_pid}'
omx team config set myteam hud_pane_pid <actual-pid>
omx team shutdown myteam
Defensive patterns

Strategy: type-guard

Validate before calling

const proof = readExactPaneProofSync(config.hud_pane_id);
if (proof.status === 'live' && proof.pid !== config.hud_pane_pid) throw new Error('HUD pane identity drifted; refresh config');

Type guard

function hudPaneIdentityMatches(cfg: TeamConfig): boolean {
  if (typeof cfg.hud_pane_id !== 'string' || typeof cfg.hud_pane_pid !== 'number') return true;
  const p = readExactPaneProofSync(cfg.hud_pane_id);
  return p.status !== 'live' || p.pid === cfg.hud_pane_pid;
}

Try / catch

try { await shutdownTeam(t, cwd, {}); } catch (e) { if (/^shutdown_shared_session_HUD_pane_identity_changed:/.test((e as Error).message)) { await refreshHudPaneIds(t); await shutdownTeam(t, cwd, {}); } else throw e; }

Prevention

When it happens

Trigger: Shutting down a shared-session team where the HUD pane died and tmux reused the same %pane-id for another process, while config still records the old hud_pane_pid.

Common situations: HUD pane crashed and pane ID got recycled; tmux server restart with pane renumbering; stale team config referencing an old HUD pane.

Related errors


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