Yeachan-Heo/oh-my-codex · error · ExactPaneProofUnavailableError
unavailable
Error message
unavailable
What it means
ExactPaneProofUnavailableError thrown from requireLiveExactPaneSync: the global pane snapshot (readExactPaneProofSync) could not decide liveness — status 'unavailable' (full message: exact_pane_proof_unavailable:<paneId>:<reason>). The library fails closed: without proof, it neither acts nor assumes the pane is gone.
Source
Thrown at src/team/tmux-session.ts:584
const topology = listPanesResult(leader);
const hudMatches = !topology.error && topology.panes.filter((pane) => pane.paneId === debt.pane_id
&& hudPaneMatchesOwner(pane, { leaderPaneId: debt.hud_owner_leader_pane_id })).length === 1;
if (!hudMatches) throw new Error(`restored_hud_cleanup_debt_unresolved:${debt.pane_id}`);
const finalProof = readExactPaneProofSync(debt.pane_id);
if (finalProof.status !== 'live' || finalProof.pid !== debt.pane_pid) {
throw new Error(`restored_hud_cleanup_debt_unresolved:${debt.pane_id}`);
}
removeRestoredHudCleanupDebtSync(record.path);
}
/**
* Kill only a pane that a fresh global snapshot proves live. Callers treat
* gone/dead rows as already cleaned and unavailable snapshots as fail-closed.
*/
function requireLiveExactPaneSync(paneId: string, expectedPid?: number): string {
const proof = readExactPaneProofSync(paneId);
if (proof.status === 'unavailable') throw new ExactPaneProofUnavailableError(proof);
if (proof.status === 'gone') throw new Error(`tmux pane is not proven live: ${paneId}`);
if (expectedPid !== undefined && proof.pid !== expectedPid) {
throw new Error(`tmux pane identity changed: ${paneId}`);
}
return proof.paneId;
}
function killExactPaneSync(paneId: string, expectedPid?: number, assertAuthorization?: () => void): void {
const proof = readExactPaneProofSync(paneId);
if (proof.status === 'unavailable') throw new ExactPaneProofUnavailableError(proof);
if (proof.status === 'gone') return;
if (expectedPid !== undefined && proof.pid !== expectedPid) {
throw new Error(`tmux pane identity changed: ${paneId}`);
}
assertAuthorization?.();
// Authorization can read tmux. Re-prove immediately after it so a recycled
// pane ID cannot be targeted by the subsequent kill.
const finalProof = readExactPaneProofSync(proof.paneId);View on GitHub (pinned to 3ad79a8a6f)
Solutions
- Check proof.reason in the error object: 'no server' means nothing is running (treat panes as gone if appropriate for your flow)
- Fix environment: consistent TMUX/TMUX_TMPDIR, tmux on PATH
- Retry after the tmux server is back; surface unavailability distinctly from identity failures
Example fix
// before
requireLiveExactPaneSync(paneId);
// after
try { requireLiveExactPaneSync(paneId); }
catch (e) {
if (e.message.startsWith('exact_pane_proof_unavailable:')) { /* fail-closed: reschedule */ }
else throw e;
} Defensive patterns
Strategy: retry
Validate before calling
if (!runTmuxStructured(['list-sessions']).ok) throw new Error('tmux server unreachable; deferring pane ops'); Type guard
function isProofUnavailable(e: unknown): boolean { return e instanceof Error && e.message.startsWith('exact_pane_proof_unavailable:'); } Try / catch
catch (e) { if (isProofUnavailable(e)) { deferAndRetry(); return; } throw e; } Prevention
- Distinguish unavailability (transient, retry) from identity change (permanent)
- Keep tmux on PATH and TMUX socket env consistent
When it happens
Trigger: tmux list-panes global snapshot fails or times out: server not running, socket unreachable, tmux binary missing, or spawn error. Any requireLiveExactPaneSync call can raise it.
Common situations: tmux server died; TMUX_TMPDIR/TMUX env mismatch so the client talks to the wrong socket; tmux not installed on PATH; resource exhaustion preventing process spawn.
Related errors
- invalid auth slot path
- auth directory must not be a symlink: ${dir}
- auth path is not a directory: ${dir}
- ${label} is not a file: ${path}
- ${label} not found: ${path}
AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27).
Data as JSON: /api/errors/c49f9199dfc01281.
Report an issue: GitHub.