Yeachan-Heo/oh-my-codex · error · Error
shutdown_ _ _identity_changed
Error message
shutdown_${scope}_${kind.replaceAll(' ', '_')}_identity_changed:${authorization.paneId} What it means
Thrown by assertSharedPaneAuthorizationContinuous when, mid-shutdown, a pane's live proof is gone or its PID changed relative to the frozen authorization. It guards against the pane being swapped between authorization and the destructive teardown step.
Solutions
- Avoid touching the shared session (manual kills, respawn hooks) while shutdown is running
- Disable automatic respawn (remain-on-exit off, respawn-pane hooks) during teardown, or make them idempotent
- Retry the shutdown operation — if the pane died naturally, the next run should skip it
Defensive patterns
Strategy: retry
Try / catch
catch (e) { if (String(e.message).includes('_identity_changed:')) { await sleep(500); return shutdown(retries + 1); } throw e; } Prevention
- Don't manually close/respawn panes during shutdown
- Disable respawn hooks for team panes
When it happens
Trigger: After freezeSharedPaneAuthorization captured {paneId,pid}, readExactPaneProofSync returns non-live or a different pid before/after teardown steps — pane exited or was respawned during shutdown.
Common situations: Long-running teardown steps where tmux respawns panes (remain-on-exit + respawn hooks); user manually closing panes during shutdown; flaky proof file persistence.
Related errors
- failed to capture tmux source authority
- shutdown_shared_session_
- tmux pane is not proven live
- failed to capture tmux pane owner
- failed to kill tmux pane
AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27).
Data as JSON: /api/errors/e3da9375150fbbf8.
Report an issue: GitHub.
Appendix: source
Thrown at src/team/runtime.ts:5205
}
}
const owner = readPaneTeamOwnerTagResult(paneId);
if (owner.status === 'error') {
throw new Error(`shutdown_shared_session_${kind.replaceAll(' ', '_')}_owner_unavailable:${paneId}:${owner.error}`);
}
if (owner.status !== 'value' || !tmuxPaneOwnerId || owner.value !== tmuxPaneOwnerId) {
throw new Error(`shutdown_shared_session_${kind.replaceAll(' ', '_')}_owner_changed:${paneId}`);
}
return { paneId, pid: proof.pid, owner: owner.value };
};
const assertSharedPaneAuthorizationContinuous = (
authorization: FrozenSharedPaneAuthorization,
kind: 'HUD pane' | 'restore leader pane',
): void => {
const scope = sharedSessionTopology ? 'shared_session' : 'detached_session';
const proof = readExactPaneProofSync(authorization.paneId);
if (proof.status !== 'live' || proof.pid !== authorization.pid) {
throw new Error(`shutdown_${scope}_${kind.replaceAll(' ', '_')}_identity_changed:${authorization.paneId}`);
}
const owner = readPaneTeamOwnerTagResult(authorization.paneId);
if (owner.status === 'error') {
throw new Error(`shutdown_${scope}_${kind.replaceAll(' ', '_')}_owner_unavailable:${authorization.paneId}:${owner.error}`);
}
const currentOwner = owner.status === 'value' ? owner.value : null;
if (currentOwner !== authorization.owner) {
throw new Error(`shutdown_${scope}_${kind.replaceAll(' ', '_')}_owner_changed:${authorization.paneId}`);
}
};
const persistedHudPaneId = typeof hudPaneId === 'string' && /^%[0-9]+$/.test(hudPaneId)
? hudPaneId
: null;
const persistedLeaderPaneId = typeof leaderPaneId === 'string' && /^%[0-9]+$/.test(leaderPaneId)
? leaderPaneId
: null;
if (persistedHudPaneId && effectiveHudPaneId === persistedHudPaneId && (typeof hudPanePid !== 'number' || !Number.isSafeInteger(hudPanePid) || hudPanePid <= 0)) {
const scope = sharedSessionTopology ? 'shared_session' : 'detached_session';View on GitHub (pinned to 3ad79a8a6f)