Yeachan-Heo/oh-my-codex · error · Error
shutdown_${scope}_${kind.replaceAll(' ', '_')}_identity_chan
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.
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)
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
- shutdown_shared_session_${kind.replaceAll(' ', '_')}_proof_u
- failed to capture tmux source authority: ${result.stderr}
- tmux pane is not proven live: ${normalizedLeaderPaneId}
- invalid auth slot path
- ${label} is not a file: ${path}
AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27).
Data as JSON: /api/errors/e3da9375150fbbf8.
Report an issue: GitHub.