{"record":{"id":"edc0a2b16f06db48","repo":"Yeachan-Heo/oh-my-codex","slug":"run-session-pointer-changed","errorCode":null,"errorMessage":"run session pointer changed","messagePattern":"run session pointer changed","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/cli/index.ts","lineNumber":8154,"sourceCode":"    if (!record || file !== `${record.context_key}.json`) continue;\n    if (!record.session_id || normalizeSessionId(record.session_id) !== record.session_id) continue;\n    if (!hasMatchingMadmaxDetachedRuntimeBinding(record)) continue;\n    if (\n      canonicalizePathForRunDirMatch(record.source_cwd) !== canonicalCwd\n      && (!record.worktree_cwd || canonicalizePathForRunDirMatch(record.worktree_cwd) !== canonicalCwd)\n    ) continue;\n\n    try {\n      const canonicalRunDir = realpathSync(resolve(record.run_dir));\n      if (!isCanonicalPathWithin(canonicalRunsRoot, canonicalRunDir)) {\n        throw new Error(\"run directory escapes the authorized runs root\");\n      }\n      const stateDir = realpathSync(join(canonicalRunDir, \".omx\", \"state\"));\n      if (!isCanonicalPathWithin(canonicalRunDir, stateDir)) {\n        throw new Error(\"state directory escapes the authorized run directory\");\n      }\n      const session = JSON.parse(await readFile(join(stateDir, \"session.json\"), \"utf-8\")) as Record<string, unknown>;\n      if (session.session_id !== record.session_id) throw new Error(\"run session pointer changed\");\n      const sessionDir = realpathSync(join(stateDir, \"sessions\", record.session_id));\n      if (!isCanonicalPathWithin(stateDir, sessionDir)) {\n        throw new Error(\"session directory escapes the authorized state directory\");\n      }\n      candidates.push({ sessionDir, sessionId: record.session_id, record });\n    } catch (err) {\n      throw new Error(`Refusing cancellation because detached run authority is invalid: ${record.run_dir}.`, { cause: err });\n    }\n  }\n\n  if (candidates.length > 1) throw new Error(\"Refusing cancellation because multiple detached run authorities match.\");\n  if (candidates.length === 0) return null;\n  const [{ sessionDir, sessionId, record }] = candidates;\n  const refs: ModeStateFileRef[] = [];\n  const stateFiles = await readdir(sessionDir).catch(() => [] as string[]);\n  for (const file of stateFiles) {\n    if (!isModeStateFilename(file)) continue;\n    const path = join(sessionDir, file);","sourceCodeStart":8136,"sourceCodeEnd":8172,"githubUrl":"https://github.com/Yeachan-Heo/oh-my-codex/blob/3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2/src/cli/index.ts#L8136-L8172","documentation":"The session.json pointer inside the run's state dir no longer matches the session_id recorded in the detached active record, indicating the run's session identity changed under the cancellation caller.","triggerScenarios":"session.json was rewritten by a newer run in the same run dir, or the active record references an old session_id after the session was restarted.","commonSituations":"Session restarted/upgraded in place, leftover active record from a previous session, or multiple sessions sharing one run dir.","solutions":["Delete the stale detached active record and retry cancellation against the current session","Re-run with the CLI's discovery flow so records and session.json stay in sync","Ensure one session per run dir; clean old active records after restarts"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const session = JSON.parse(await readFile(join(stateDir, 'session.json'), 'utf8'));\nif (session.session_id !== record.session_id) throw new Error('record is stale — refresh records');","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Prune active records after session restarts","One session per run dir","Re-discover sessions through the CLI, not manual record edits"],"tags":["state-mismatch","session-management"],"backgroundTag":"stale-session-state","analyzedSha":"3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2","analyzedAt":"2026-08-27T22:18:39.783Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}