Yeachan-Heo/oh-my-codex · error · SessionPointerLaunchAbort
session_pointer_owner_conflict
session_pointer_owner_conflict
Error message
Session pointer ${state.session_id} conflicts with requested session ${candidateSessionId}. What it means
ownerConflictAbort: an existing usable pointer's state does not describe this caller. The guard checks that the stored session_id and native_session_id both normalize to the requested nativeSessionId, the platform matches, the state is authoritative for this cwd, and the recorded pid equals the resolved pid; any mismatch means another session owns this slot.
Source
Thrown at src/hooks/session.ts:3362
&& !(pointer.status === 'identity-indeterminate' && isUnobservableLivePointerState(pointer.state))
) {
throw unusablePointerAbort(context, nativeSessionId, pointer);
}
const pid = resolvePid(options);
const platform = options.platform ?? process.platform;
const linuxIdentity = sessionIdentityFor(pid, platform);
const existing = pointer.status === 'usable'
|| (pointer.status === 'identity-indeterminate' && isUnobservableLivePointerState(pointer.state))
? pointer.state
: undefined;
if (existing && (
normalizeSessionId(existing.session_id) !== nativeSessionId
|| normalizeSessionId(existing.native_session_id) !== nativeSessionId
|| existing.platform !== platform
|| !isSessionStateAuthoritativeForCwd(existing, context.cwd)
|| existing.pid !== pid
)) {
throw ownerConflictAbort(context, nativeSessionId, existing);
}
return createSessionState(context.cwd, context.baseStateDir, nativeSessionId, pid, platform, linuxIdentity, {
nativeSessionId,
startedAt: existing?.started_at,
tmuxSessionName: options.tmuxSessionName ?? existing?.tmux_session_name,
tmuxPaneId: options.tmuxPaneId ?? existing?.tmux_pane_id,
});
};
}
export async function writeNativeSessionOwner(
cwd: string,
nativeSessionId: string,
options: SessionStartOptions = {},
): Promise<SessionState> {
const normalized = normalizeSessionId(nativeSessionId);
const context = resolveNativeSessionOwnerContext(cwd, nativeSessionId);
const result = await writePointerTransaction(View on GitHub (pinned to 3ad79a8a6f)
Solutions
- Use a distinct session ID for each concurrent session; never reuse IDs across terminals.
- Re-run the begin from the same working directory the session was created in.
- If the previous owner is genuinely dead and you intend to take over, end/clear that session first via the library's end-session API.
- Do not copy state directories across platforms/machines.
Example fix
# before omx begin --session my-fixed-id # second terminal, same id # after omx begin # let the tool derive a unique session id per invocation
Defensive patterns
Strategy: validation
Validate before calling
const stored = JSON.parse(await fsp.readFile(pointerPath, 'utf8'));
if (normalize(stored.session_id) !== nativeSessionId || stored.pid !== process.pid) throw new Error('slot owned by another session'); Type guard
const iOwnSlot = (s: SessionState, id: string, pid: number): boolean => normalizeSessionId(s.session_id) === id && s.pid === pid;
Try / catch
try { await begin(...); } catch (e) { if (errCode(e) === 'session_pointer_owner_conflict') { await endSession(cwd, existingId); return begin(...); } throw e; } Prevention
- Never hardcode session IDs across terminals.
- Run each session from its original cwd.
- End stale sessions explicitly instead of forcing new ones over them.
When it happens
Trigger: Calling begin/create with a session ID (or from a cwd) that already has a usable pointer belonging to a different session/pid/platform — e.g. reusing a session ID across two terminals, or running from a different working directory than where the session was created.
Common situations: Hardcoded or user-supplied session IDs colliding between parallel shells; the same state dir shared by multiple projects (cwd authority mismatch); platform mismatch after migrating state between macOS and Linux; pid reuse after a crash where the stale pid no longer matches.
Related errors
- session_pointer_context_failure
- Cannot advance Autopilot from ralplan to ultragoal with forg
- status must be one of running, blocked, failed, complete
- autopilot.session_id must match the selected writable sessio
- 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/cf7ef573cd928c89.
Report an issue: GitHub.