Yeachan-Heo/oh-my-codex · error · Error
startup_cleanup_pane_owner_unavailable:missing_team_owner_id
Error message
startup_cleanup_pane_owner_unavailable:missing_team_owner_id
What it means
reconcileStartupCleanupPanes must kill leftover startup panes via tmux, and to do that safely it needs the team's pane-owner tag ID (tmux_pane_owner_id) to verify ownership. If cleanup panes are configured but that owner id is missing/blank, there is no way to prove the panes belong to this team, so it refuses rather than risk killing foreign panes.
Source
Thrown at src/team/runtime.ts:384
startup_cleanup_panes: current.startup_cleanup_panes,
}, null, 2),
},
});
const committed = await readTeamConfig(current.name, cwd);
if (!committed) throw new Error(`shutdown_config_missing_after_commit:${current.name}`);
return committed;
});
}
export async function reconcileStartupCleanupPanes(
config: TeamConfig,
cwd: string,
): Promise<TeamConfig> {
const cleanupPanes = config.startup_cleanup_panes ?? [];
if (cleanupPanes.length === 0) return config;
const teamPaneOwnerId = config.tmux_pane_owner_id?.trim() ?? '';
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}`);View on GitHub (pinned to 3ad79a8a6f)
Solutions
- Restore/set tmux_pane_owner_id in the team config (a non-empty unique owner tag)
- Clear startup_cleanup_panes if the panes are already gone and no owner proof is needed
- Recreate the team with the current version so the config is fully populated
Example fix
// before
{ startup_cleanup_panes: [{pane_id: '%5', pid: 123}] }
// after
{ tmux_pane_owner_id: 'omx-team-myteam-ab12', startup_cleanup_panes: [{pane_id: '%5', pid: 123}] } Defensive patterns
Strategy: validation
Validate before calling
if ((config.startup_cleanup_panes?.length ?? 0) > 0 && !(config.tmux_pane_owner_id?.trim())) {
config.startup_cleanup_panes = undefined; // or fail with a clear message
} Try / catch
try { await reconcileStartupCleanupPanes(config, cwd); } catch (e) { if (e instanceof Error && e.message === 'startup_cleanup_pane_owner_unavailable:missing_team_owner_id') { /* populate owner id or clear cleanup panes */ } throw e; } Prevention
- Never hand-edit startup_cleanup_panes without tmux_pane_owner_id
- Migrate legacy configs by restarting the team
When it happens
Trigger: A config with non-empty startup_cleanup_panes but tmux_pane_owner_id unset, empty, or whitespace — typically hand-edited or migrated configs predating the owner-tag feature.
Common situations: Configs created by an older version before tmux_pane_owner_id existed; manual config.json edits stripping the field; tests with minimal fixture configs.
Related errors
- startup_cleanup_pane_target_invalid:${cleanupPane.pane_id}
- startup_cleanup_pane_owner_changed:${cleanupPane.pane_id}
- tmux target validation failed: ${resolved.reason}
- startup_cleanup_pane_pid_missing:${cleanupPane.pane_id}
- startup_cleanup_pane_identity_changed:${cleanupPane.pane_id}
AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27).
Data as JSON: /api/errors/355d2292ccbe371a.
Report an issue: GitHub.