{"record":{"id":"e7e8b2f5c0575d6b","repo":"Yeachan-Heo/oh-my-codex","slug":"timed-out-waiting-for-tmux-extended-keys-lease-loc","errorCode":null,"errorMessage":"timed out waiting for tmux extended-keys lease lock: ${lockPath}","messagePattern":"timed out waiting for tmux extended-keys lease lock: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/cli/index.ts","lineNumber":4872,"sourceCode":"        let holderAlive = false;\n        try {\n          const holderPid = Number.parseInt(readFileSync(join(lockPath, \"pid\"), \"utf-8\").trim(), 10);\n          if (Number.isFinite(holderPid) && holderPid > 0) {\n            process.kill(holderPid, 0);\n            holderAlive = true;\n          }\n        } catch {\n          // PID file missing/unreadable or process dead (ESRCH) — treat as stale\n        }\n        if (!holderAlive) {\n          rmSync(lockPath, { recursive: true, force: true });\n          continue;\n        }\n      }\n      blockMs(TMUX_EXTENDED_KEYS_LOCK_RETRY_MS);\n    }\n  }\n  throw new Error(`timed out waiting for tmux extended-keys lease lock: ${lockPath}`);\n}\n\ninterface DetachedLeaderPreLaunchOptions {\n  notifyTempContract?: NotifyTempContract;\n  enableNotifyFallbackAuthority: boolean;\n  worktreeDirty: boolean;\n  shouldAttach?: boolean;\n}\n\nfunction buildDetachedSessionLeaderCommand(\n  cwd: string,\n  sessionName: string,\n  codexCmd: string,\n  sessionId: string | undefined,\n  codexHomeOverride: string | undefined,\n  projectLocalCodexHomeForCleanup: string | undefined,\n  runtimeCodexHomeForCleanup: string | undefined,\n  parentEnvFilePath: string | undefined,","sourceCodeStart":4854,"sourceCodeEnd":4890,"githubUrl":"https://github.com/Yeachan-Heo/oh-my-codex/blob/3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2/src/cli/index.ts#L4854-L4890","documentation":"A inter-process lock file used to serialize tmux extended-keys configuration changes could not be acquired within the retry budget. The code loops retrying the lock with a fixed sleep (TMUX_EXTENDED_KEYS_LOCK_RETRY_MS) and a timeout, then throws with the lock path.","triggerScenarios":"Multiple OMX invocations (e.g. concurrent sessions, a launch storm, or a stuck previous process holding the lock file) contend for the tmux extended-keys lease lock; a stale lock from a killed process with no cleanup, or many parallel detached launches, exhausts the timeout.","commonSituations":"Scripts that launch several OMX sessions concurrently; a previously SIGKILLed process leaving a stale lock file in state/; slow or hung filesystems (NFS) making the lock appear held; CI environments running parallel matrix jobs sharing a home dir.","solutions":["Find and remove the stale lock file at the path in the error message once no OMX process is running","Reduce concurrency: serialize session launches so only one process configures tmux extended-keys at a time","Check for orphaned omx/tmux processes (ps aux | grep omx) and kill them before retrying","Retry the command after the timeout — transient contention resolves itself when the holder exits"],"exampleFix":"// before\nawait Promise.all(Array.from({length: 5}, () => startSession()));\n\n// after\nfor (const job of jobs) { await startSession(); } // serialize to avoid lock contention","handlingStrategy":"retry","validationCode":"const holder = tryAcquireLock(lockPath, { staleMs: 30_000 });\nif (!holder) { /* skip extended-keys config this run or wait */ }","typeGuard":null,"tryCatchPattern":"try { configureExtendedKeys(); } catch (e) { if (e instanceof Error && e.message.includes(\"lease lock\")) { await sleep(5_000); return configureExtendedKeys(); /* bounded retry */ } throw e; }","preventionTips":["Serialize concurrent OMX launches in scripts (queue or limit=1)","Remove stale lock files after killing OMX processes","Treat lock timeout as transient: retry before treating as fatal"],"tags":["tmux","lock","timeout","concurrency"],"backgroundTag":"file-lock-timeout","analyzedSha":"3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2","analyzedAt":"2026-08-27T22:18:39.783Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}