{"record":{"id":"cf7ef573cd928c89","repo":"Yeachan-Heo/oh-my-codex","slug":"session-pointer-owner-conflict","errorCode":"session_pointer_owner_conflict","errorMessage":"Session pointer ${state.session_id} conflicts with requested session ${candidateSessionId}.","messagePattern":"Session pointer (.+?) conflicts with requested session (.+?)\\.","errorType":"exception","errorClass":"SessionPointerLaunchAbort","httpStatus":null,"severity":"error","filePath":"src/hooks/session.ts","lineNumber":3362,"sourceCode":"      && !(pointer.status === 'identity-indeterminate' && isUnobservableLivePointerState(pointer.state))\n    ) {\n      throw unusablePointerAbort(context, nativeSessionId, pointer);\n    }\n    const pid = resolvePid(options);\n    const platform = options.platform ?? process.platform;\n    const linuxIdentity = sessionIdentityFor(pid, platform);\n    const existing = pointer.status === 'usable'\n      || (pointer.status === 'identity-indeterminate' && isUnobservableLivePointerState(pointer.state))\n      ? pointer.state\n      : undefined;\n    if (existing && (\n      normalizeSessionId(existing.session_id) !== nativeSessionId\n      || normalizeSessionId(existing.native_session_id) !== nativeSessionId\n      || existing.platform !== platform\n      || !isSessionStateAuthoritativeForCwd(existing, context.cwd)\n      || existing.pid !== pid\n    )) {\n      throw ownerConflictAbort(context, nativeSessionId, existing);\n    }\n    return createSessionState(context.cwd, context.baseStateDir, nativeSessionId, pid, platform, linuxIdentity, {\n      nativeSessionId,\n      startedAt: existing?.started_at,\n      tmuxSessionName: options.tmuxSessionName ?? existing?.tmux_session_name,\n      tmuxPaneId: options.tmuxPaneId ?? existing?.tmux_pane_id,\n    });\n  };\n}\n\nexport async function writeNativeSessionOwner(\n  cwd: string,\n  nativeSessionId: string,\n  options: SessionStartOptions = {},\n): Promise<SessionState> {\n  const normalized = normalizeSessionId(nativeSessionId);\n  const context = resolveNativeSessionOwnerContext(cwd, nativeSessionId);\n  const result = await writePointerTransaction(","sourceCodeStart":3344,"sourceCodeEnd":3380,"githubUrl":"https://github.com/Yeachan-Heo/oh-my-codex/blob/3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2/src/hooks/session.ts#L3344-L3380","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before\nomx begin --session my-fixed-id   # second terminal, same id\n\n# after\nomx begin   # let the tool derive a unique session id per invocation","handlingStrategy":"validation","validationCode":"const stored = JSON.parse(await fsp.readFile(pointerPath, 'utf8'));\nif (normalize(stored.session_id) !== nativeSessionId || stored.pid !== process.pid) throw new Error('slot owned by another session');","typeGuard":"const iOwnSlot = (s: SessionState, id: string, pid: number): boolean =>\n  normalizeSessionId(s.session_id) === id && s.pid === pid;","tryCatchPattern":"try { await begin(...); } catch (e) { if (errCode(e) === 'session_pointer_owner_conflict') { await endSession(cwd, existingId); return begin(...); } throw e; }","preventionTips":["Never hardcode session IDs across terminals.","Run each session from its original cwd.","End stale sessions explicitly instead of forcing new ones over them."],"tags":["session","conflict","ownership","pid","cwd"],"backgroundTag":"session-owner-conflict","analyzedSha":"3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2","analyzedAt":"2026-08-27T22:18:39.783Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}