{"record":{"id":"2fab566d6aaa0ef9","repo":"Yeachan-Heo/oh-my-codex","slug":"auth-directory-must-not-be-a-symlink-dir","errorCode":null,"errorMessage":"auth directory must not be a symlink: ${dir}","messagePattern":"auth directory must not be a symlink: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/auth/paths.ts","lineNumber":57,"sourceCode":"}\n\nexport function resolveDefaultCodexHome(home = homedir()): string {\n  return join(home, \".codex\");\n}\n\nexport function resolveLiveAuthPath(\n  cwd = process.cwd(),\n  env: NodeJS.ProcessEnv = process.env,\n  home = homedir(),\n): string {\n  const codexHome = resolveCodexHomeForLaunch(cwd, env) || resolveDefaultCodexHome(home);\n  return join(codexHome, \"auth.json\");\n}\n\nexport async function ensurePrivateDir(dir: string): Promise<void> {\n  await mkdir(dir, { recursive: true, mode: AUTH_DIR_MODE });\n  const info = await lstat(dir);\n  if (info.isSymbolicLink()) throw new Error(`auth directory must not be a symlink: ${dir}`);\n  if (!info.isDirectory()) throw new Error(`auth path is not a directory: ${dir}`);\n  if (process.platform !== \"win32\") {\n    const { chmod } = await import(\"fs/promises\");\n    await chmod(dir, AUTH_DIR_MODE).catch(() => undefined);\n  }\n}\n\nexport async function assertReadableFile(path: string, label: string): Promise<void> {\n  try {\n    const info = await stat(path);\n    if (!info.isFile()) throw new Error(`${label} is not a file: ${path}`);\n  } catch (err) {\n    if (err && typeof err === \"object\" && \"code\" in err && err.code === \"ENOENT\") {\n      throw new Error(`${label} not found: ${path}`);\n    }\n    throw err;\n  }\n}","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/Yeachan-Heo/oh-my-codex/blob/3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2/src/auth/paths.ts#L39-L75","documentation":"The second-pass batch proof in requireFrozenWindowTopologySync found a pane that is definitively gone ('gone') while the frozen topology still expects it live. This catches panes that died during the tiny window between the first and second validation passes (or after passing pass one).","triggerScenarios":"A pane exiting or being killed between the first per-pane proof and the final batched proof within a single topology validation call.","commonSituations":"Worker processes exiting under load, scripted pane kills racing the operation, or remain-on-exit off combined with flaky worker processes.","solutions":["Enable remain-on-exit on team panes so exited panes stay until deliberately killed","Fix worker processes that exit prematurely","Retry/rebuild: a lost pane invalidates the frozen topology — recreate the session","Coordinate all pane-killing through the library's own teardown APIs"],"exampleFix":"# keep dead panes around so topology checks stay consistent\ntmux set-option -t myteam remain-on-exit on","handlingStrategy":"validation","validationCode":"runTmuxOk(['set-option', '-t', sessionName, 'remain-on-exit', 'on']);","typeGuard":null,"tryCatchPattern":"catch (err) { if (/not proven live/.test(err.message)) { rebuildTeamSession(); } }","preventionTips":["remain-on-exit on for team panes","Fix prematurely exiting workers","Route all kills through library teardown"],"tags":["tmux","pane-exited","toctou","topology"],"backgroundTag":"tmux-pane-exited","analyzedSha":"3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2","analyzedAt":"2026-08-27T22:18:39.783Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}