Yeachan-Heo/oh-my-codex · error · Error
startup_cleanup_pane_owner_changed:${cleanupPane.pane_id}
Error message
startup_cleanup_pane_owner_changed:${cleanupPane.pane_id} What it means
The pane's owner tag was read successfully but its value does not match the team's tmux_pane_owner_id (or is absent). The pane was expected to be owned by this team but is tagged otherwise (or untagged), so killing it could destroy another team's pane and the reconcile aborts.
Source
Thrown at src/team/runtime.ts:412
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,
hudPaneId: config.hud_pane_id,
expectedPanePids,
authorizePaneKill: (paneId, proof) => {
if (expectedPanePids[paneId] !== proof.pid) return false;
const owner = readPaneTeamOwnerTagResult(paneId);
return owner.status === 'value' && owner.value === teamPaneOwnerId;
},
});
assertPaneTeardownProofsAvailable('startup_cleanup', teardown.proofUnavailable);
for (const paneId of teardown.killedPaneIds) resolvedPaneIds.add(paneId);View on GitHub (pinned to 3ad79a8a6f)
Solutions
- Inspect the pane's owner tag (`tmux show-options -p -t <pane> @team-owner` style) and determine which team owns it
- Kill the pane manually if you confirm it is leftover, then remove it from startup_cleanup_panes
- Avoid running multiple teams against the same tmux session unless the runtime supports it
Defensive patterns
Strategy: try-catch
Validate before calling
const owner = readPaneTeamOwnerTagResult(paneId);
if (owner.status === 'value' && owner.value !== teamPaneOwnerId) { /* foreign pane: exclude from cleanup */ } Try / catch
try { await reconcileStartupCleanupPanes(config, cwd); } catch (e) { if (e instanceof Error && e.message.startsWith('startup_cleanup_pane_owner_changed:')) { /* inspect @team-owner option; exclude or kill manually */ } throw e; } Prevention
- Don't run multiple teams in one tmux session
- Don't manually edit tmux user options on team panes
When it happens
Trigger: Two teams sharing a tmux session with overlapping pane expectations; a pane re-tagged by a different team; panes whose user option was never set because they predate tagging.
Common situations: Multiple concurrent teams in one tmux session; resume-after-crash where pane tags were lost; manual tmux option edits.
Related errors
- startup_cleanup_pane_owner_unavailable:missing_team_owner_id
- startup_cleanup_pane_target_invalid:${cleanupPane.pane_id}
- startup_cleanup_pane_pid_missing:${cleanupPane.pane_id}
- startup_cleanup_pane_identity_changed:${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/365deabfe8bfeb20.
Report an issue: GitHub.