{"record":{"id":"b7de65e814d68896","repo":"NousResearch/hermes-agent","slug":"timed-out-waiting-for-the-terminal-cwd-write-if","errorCode":null,"errorMessage":"Timed out waiting for the TERMINAL_CWD {'write' if _holds_cwd_write else 'read'} lock after {_cwd_lock_timeout:.0f}s — another cron job (a workdir writer, or long-running readers) has held it for longer than the cron inactivity limit. If a workdir job is the holder, stagger its schedule or remove its workdir to unblock this job (#79768).","messagePattern":"Timed out waiting for the TERMINAL_CWD (.+?) lock after (.+?)s — another cron job \\(a workdir writer, or long-running readers\\) has held it for longer than the cron inactivity limit\\. If a workdir job is the holder, stagger its schedule or remove its workdir to unblock this job \\(#79768\\)\\.","errorType":"exception","errorClass":"TimeoutError","httpStatus":null,"severity":"error","filePath":"cron/scheduler.py","lineNumber":3878,"sourceCode":"            _cwd_lock_acquired = False\n\n    # Everything after the acquire MUST live inside this try, so the finally\n    # below always releases the lock even if the env override or any later\n    # statement raises.  A leaked writer would deadlock the whole scheduler\n    # (every future job blocks on acquire_*); a leaked reader blocks all\n    # future writers.  Acquire itself can't leak (it either blocks or returns).\n    _cron_session_var = _VAR_MAP[\"HERMES_CRON_SESSION\"]\n    _cron_session_token = None\n    _non_dispatcher_token = None\n    try:\n        if not _cwd_lock_acquired:\n            # Fail closed (#79768): running without the lock would let a\n            # concurrent workdir job's process-global TERMINAL_CWD override\n            # leak into this job's shell/file/code-exec commands — silent\n            # wrong-directory execution, the exact corruption the lock\n            # exists to prevent. A loud failure is recoverable (next tick /\n            # manual rerun); a job that ran in the wrong directory is not.\n            raise TimeoutError(\n                f\"Timed out waiting for the TERMINAL_CWD \"\n                f\"{'write' if _holds_cwd_write else 'read'} lock after \"\n                f\"{_cwd_lock_timeout:.0f}s — another cron job (a workdir \"\n                f\"writer, or long-running readers) has held it for longer \"\n                f\"than the cron inactivity limit. If a workdir job is the \"\n                f\"holder, stagger its schedule or remove its workdir to \"\n                f\"unblock this job (#79768).\"\n            )\n        # Scope cron approval policy to this job. Keep the token so the finally\n        # restores the pre-job state instead of pinning an explicit empty value,\n        # which would suppress the legacy os.environ fallback used by standalone\n        # cron entrypoints and tests.\n        _cron_session_token = _cron_session_var.set(\"1\")\n\n        # Mark this job as NOT the dispatcher-owned kanban worker.\n        #\n        # A kanban worker is a normal `hermes chat -q` CLI agent whose default\n        # toolset includes `cronjob`, running with HERMES_KANBAN_TASK","sourceCodeStart":3860,"sourceCodeEnd":3896,"githubUrl":"https://github.com/NousResearch/hermes-agent/blob/c896c09c42910c584c4c7d2325b58c14713ea42c/cron/scheduler.py#L3860-L3896","documentation":"Error \"Timed out waiting for the TERMINAL_CWD {'write' if _holds_cwd_write else 'read'} lock after {_cwd_lock_timeout:.0f}s — another cron job (a workdir writer, or long-running readers) has held it for longer than the cron inactivity limit. If a workdir job is the holder, stagger its schedule or remove its workdir to unblock this job (#79768).\" thrown in NousResearch/hermes-agent.","triggerScenarios":"Thrown at cron/scheduler.py:3878 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Stagger schedules of workdir jobs so they do not hold the TERMINAL_CWD lock past the inactivity limit.","Remove the workdir from the offending job, or shorten long-running jobs sharing the cwd lock."],"exampleFix":null,"handlingStrategy":null,"validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"c896c09c42910c584c4c7d2325b58c14713ea42c","analyzedAt":"2026-08-14T17:18:01.089Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}