NousResearch/hermes-agent · error · TimeoutError

Timed out waiting for the TERMINAL_CWD {'write' if _holds_cw

Error message

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).

What it means

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.

Source

Thrown at cron/scheduler.py:3878

            _cwd_lock_acquired = False

    # Everything after the acquire MUST live inside this try, so the finally
    # below always releases the lock even if the env override or any later
    # statement raises.  A leaked writer would deadlock the whole scheduler
    # (every future job blocks on acquire_*); a leaked reader blocks all
    # future writers.  Acquire itself can't leak (it either blocks or returns).
    _cron_session_var = _VAR_MAP["HERMES_CRON_SESSION"]
    _cron_session_token = None
    _non_dispatcher_token = None
    try:
        if not _cwd_lock_acquired:
            # Fail closed (#79768): running without the lock would let a
            # concurrent workdir job's process-global TERMINAL_CWD override
            # leak into this job's shell/file/code-exec commands — silent
            # wrong-directory execution, the exact corruption the lock
            # exists to prevent. A loud failure is recoverable (next tick /
            # manual rerun); a job that ran in the wrong directory is not.
            raise TimeoutError(
                f"Timed out waiting for the TERMINAL_CWD "
                f"{'write' if _holds_cwd_write else 'read'} lock after "
                f"{_cwd_lock_timeout:.0f}s — another cron job (a workdir "
                f"writer, or long-running readers) has held it for longer "
                f"than the cron inactivity limit. If a workdir job is the "
                f"holder, stagger its schedule or remove its workdir to "
                f"unblock this job (#79768)."
            )
        # Scope cron approval policy to this job. Keep the token so the finally
        # restores the pre-job state instead of pinning an explicit empty value,
        # which would suppress the legacy os.environ fallback used by standalone
        # cron entrypoints and tests.
        _cron_session_token = _cron_session_var.set("1")

        # Mark this job as NOT the dispatcher-owned kanban worker.
        #
        # A kanban worker is a normal `hermes chat -q` CLI agent whose default
        # toolset includes `cronjob`, running with HERMES_KANBAN_TASK

View on GitHub (pinned to c896c09c42)

Solutions

  1. Stagger schedules of workdir jobs so they do not hold the TERMINAL_CWD lock past the inactivity limit.
  2. Remove the workdir from the offending job, or shorten long-running jobs sharing the cwd lock.

When it happens

Trigger: Thrown at cron/scheduler.py:3878 when the library encounters an invalid state.

Common situations: See trigger scenarios.

Understand the failure class


AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14). Data as JSON: /api/errors/b7de65e814d68896. Report an issue: GitHub.