{"record":{"id":"2d7cc2fa24a5afb4","repo":"Yeachan-Heo/oh-my-codex","slug":"label-must-not-be-a-symlink-path","errorCode":null,"errorMessage":"${label} must not be a symlink: ${path}","messagePattern":"(.+?) must not be a symlink: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/auth/paths.ts","lineNumber":81,"sourceCode":"}\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}\n\nexport async function assertNoSymlink(path: string, label: string): Promise<void> {\n  try {\n    const { lstat } = await import(\"fs/promises\");\n    const info = await lstat(path);\n    if (info.isSymbolicLink()) throw new Error(`${label} must not be a symlink: ${path}`);\n  } catch (err) {\n    if (err && typeof err === \"object\" && \"code\" in err && err.code === \"ENOENT\") return;\n    throw err;\n  }\n}\n","sourceCodeStart":63,"sourceCodeEnd":87,"githubUrl":"https://github.com/Yeachan-Heo/oh-my-codex/blob/3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2/src/auth/paths.ts#L63-L87","documentation":"The worker-pane proof reader returns 'unavailable' with a reason starting 'pane_id_changed:' when the pane id no longer resolves to the same underlying pane. The library converts this into an explicit 'identity changed' error rather than a generic unavailability, because id churn means the pinned worker no longer exists as such.","triggerScenarios":"Calling worker-pane resolution when the worker pane id was recycled — pane killed and id reused, session restarted with leftover ids, or window layout changes reassigning pane ids.","commonSituations":"Persisting worker pane ids across restarts, respawn flows, or concurrent sessions on one tmux server churning pane ids.","solutions":["Re-resolve the worker pane from a fresh split instead of reusing a persisted pane id","Recreate the team session after tmux server restarts","Inspect proof.reason after 'pane_id_changed:' for the old/new id detail","Prevent other orchestrators from killing team panes"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"const proof = readExactWorkerPaneLivenessProofSync(workerPaneId); if (proof.status === 'unavailable' && proof.reason.startsWith('pane_id_changed:')) planRelaunch();","typeGuard":null,"tryCatchPattern":"catch (err) { if (/worker pane identity changed/.test(err.message)) { relaunchWorkerPane(); } }","preventionTips":["Don't persist worker pane ids across restarts","Prevent external pane kills","Re-resolve worker panes after layout changes"],"tags":["tmux","pid-reuse","pane-identity","worker"],"backgroundTag":"stale-pane-reference","analyzedSha":"3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2","analyzedAt":"2026-08-27T22:18:39.783Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}