NousResearch/hermes-agent · critical

Hermes backend did not become ready: ${detail}

Error message

Hermes backend did not become ready: ${detail}

What it means

RuntimeError raised in load_jobs() (cron/jobs.py:1094) when reading ~/.hermes/cron/jobs.json raises an IOError that the auto-repair path could not prevent — e.g. permission denied, disk I/O error, or a read failure on a file that exists. It is distinct from the corruption branch: the file's bytes could not be read at all, so no repair is attempted.

Source

Thrown at apps/desktop/electron/backend-health.ts:168

      // An explicitly missing route means the backend predates /api/health.
      // So does a gate-shaped 401 on an ANONYMOUS probe: the dashboard auth
      // gate runs ahead of the SPA catch-all, so a pre-/api/health backend
      // rejects the unknown path as unauthenticated instead of 404 and a
      // credential-free probe can never observe the 404. Timeouts, 5xx, 429,
      // and non-gate 401s keep polling health.
      if (!useStatusFallback && (isMissingHealthEndpointError(error) || isGatedMissingHealthError(error))) {
        useStatusFallback = true

        continue
      }

      await sleep(pollMs)
    }
  }

  const detail = lastError instanceof Error ? lastError.message : 'timeout'
  throw new Error(`Hermes backend did not become ready: ${detail}`)
}

View on GitHub (pinned to c896c09c42)

Solutions

  1. Check the underlying IOError in the message, then inspect permissions on jobs.json and its parent directory.
  2. Fix ownership/permissions: chown/chmod the file so the current user can read AND write it (cron also saves).
  3. Free disk space or remount a read-only filesystem read-write.
  4. If the file is a directory or otherwise mangled, move it aside and let cron recreate an empty jobs list.

Example fix

# shell — before: cron commands fail with 'Failed to read cron database'
ls -la ~/.hermes/cron/jobs.json   # owned by root:root

# after
sudo chown -R "$USER" ~/.hermes/cron && hermes cron list
Defensive patterns

Strategy: try-catch

Validate before calling

from pathlib import Path
from hermes_constants import get_hermes_home

jobs_file = get_hermes_home() / "cron" / "jobs.json"
if jobs_file.exists() and not jobs_file.is_file():
    raise SystemExit("jobs.json is not a regular file")
if jobs_file.exists():
    try:
        jobs_file.read_text()
    except OSError as e:
        raise SystemExit(f"jobs.json unreadable: {e} — fix permissions first")

Try / catch

from cron.jobs import list_jobs
try:
    jobs = list_jobs()
except RuntimeError as e:
    if "Failed to read cron database" in str(e):
        # IO problem: check ownership/permissions of jobs.json, free disk, then retry after fix
        raise

Prevention

When it happens

Trigger: load_jobs() finds jobs.json exists but open()/read() raises OSError: file owned by another user with mode 600, a read-only or full filesystem, the file being a directory, or a transient NFS/FUSE error. Any cron operation (list/create/save via hermes cron, the cronjob tool, the scheduler tick) that loads jobs hits it.

Common situations: Running `hermes cron` under sudo previously so jobs.json is root-owned; disk full; the HERMES_HOME/profile directory was restored from a backup with wrong ownership; two profiles pointed at the same home with different users.

Related errors


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