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

  1. Use a distinct session ID for each concurrent session; never reuse IDs across terminals.
  2. Re-run the begin from the same working directory the session was created in.
  3. 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.
  4. 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

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


AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27). Data as JSON: /api/errors/cf7ef573cd928c89. Report an issue: GitHub.