Yeachan-Heo/oh-my-codex · error · Error
startup_cleanup_pane_pid_missing:${cleanupPane.pane_id}
Error message
startup_cleanup_pane_pid_missing:${cleanupPane.pane_id} What it means
For a cleanup pane that still exists (tmux proof is live), the code compares the pane's current pid to the pid recorded when the pane was registered. If the recorded pid is null, there is no expected identity to compare against, so ownership cannot be proven and the reconcile throws with the pane id.
Source
Thrown at src/team/runtime.ts:402
if (!teamPaneOwnerId) throw new Error('startup_cleanup_pane_owner_unavailable:missing_team_owner_id');
const resolvedPaneIds = new Set<string>();
const expectedPanePids: Record<string, number> = {};
for (const cleanupPane of cleanupPanes) {
if (cleanupPane.pane_id === config.leader_pane_id || cleanupPane.pane_id === config.hud_pane_id) {
throw new Error(`startup_cleanup_pane_target_invalid:${cleanupPane.pane_id}`);
}
const proof = readExactPaneProofSync(cleanupPane.pane_id);
if (proof.status === 'gone') {
resolvedPaneIds.add(cleanupPane.pane_id);
continue;
}
if (proof.status === 'unavailable') {
assertPaneTeardownProofsAvailable('startup_cleanup', [proof]);
continue;
}
if (cleanupPane.pid === null) {
throw new Error(`startup_cleanup_pane_pid_missing:${cleanupPane.pane_id}`);
}
if (proof.pid !== cleanupPane.pid) {
throw new Error(`startup_cleanup_pane_identity_changed:${cleanupPane.pane_id}`);
}
const owner = readPaneTeamOwnerTagResult(cleanupPane.pane_id);
if (owner.status === 'error') {
throw new Error(`startup_cleanup_pane_owner_unavailable:${cleanupPane.pane_id}:${owner.error}`);
}
if (owner.status !== 'value' || owner.value !== teamPaneOwnerId) {
throw new Error(`startup_cleanup_pane_owner_changed:${cleanupPane.pane_id}`);
}
expectedPanePids[cleanupPane.pane_id] = cleanupPane.pid;
}
const livePaneIds = Object.keys(expectedPanePids);
if (livePaneIds.length > 0) {
const teardown = await teardownWorkerPanes(livePaneIds, {
leaderPaneId: config.leader_pane_id,View on GitHub (pinned to 3ad79a8a6f)
Solutions
- Remove the pid-less entry (and its pane, if safe) or manually kill that tmux pane
- Delete startup_cleanup_panes from the config and let a fresh start rebuild it
- Upgrade state by restarting the team under the current version
Example fix
// before
{ startup_cleanup_panes: [{pane_id: '%7', pid: null}] }
// after
tmux kill-pane -t %7 # then start team; cleanup list rebuilt with pids Defensive patterns
Strategy: validation
Validate before calling
const unprovable = (config.startup_cleanup_panes ?? []).filter(p => p.pid === null);
if (unprovable.length) { /* clear entries or kill panes manually first */ } Try / catch
try { await reconcileStartupCleanupPanes(config, cwd); } catch (e) { if (e instanceof Error && e.message.startsWith('startup_cleanup_pane_pid_missing:')) { /* kill that pane manually, drop the entry */ } throw e; } Prevention
- Ensure state written by the current version (pids persisted)
- Treat pid:null entries as unverifiable and handle before startup
When it happens
Trigger: A startup_cleanup_panes entry with pid: null for a pane that tmux reports as still alive — configs written by older versions that did not persist pids, or partial writes.
Common situations: Version upgrades adding pid tracking to existing state; race where the pane was registered before pid capture was implemented.
Related errors
- startup_cleanup_pane_identity_changed:${cleanupPane.pane_id}
- detached ready report does not bind the inert session
- startup_cleanup_pane_owner_unavailable:missing_team_owner_id
- startup_cleanup_pane_target_invalid:${cleanupPane.pane_id}
- startup_cleanup_pane_owner_unavailable:${cleanupPane.pane_id
AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27).
Data as JSON: /api/errors/035254b6f61de298.
Report an issue: GitHub.