NousResearch/hermes-agent · error
Desktop installation ID path is not a regular file.
Error message
Desktop installation ID path is not a regular file.
What it means
ValueError from update_job (cron/jobs.py:1972): after applying updates, the job is enabled and not paused but has no next_run_at, so it recomputes — and for a 'once' schedule compute_next_run returns None (run_at is past the 120s grace window). This arm catches updates that didn't touch the schedule at all but re-enabled an expired one-shot job (e.g. flipping enabled=True).
Source
Thrown at apps/desktop/electron/desktop-installation.ts:92
}
waitForRepair()
continue
}
try {
const winner = readInstallationId(filePath)
if (winner) {
return winner
}
try {
const stat = fs.lstatSync(filePath)
if (!stat.isFile() && !stat.isSymbolicLink()) {
throw new Error('Desktop installation ID path is not a regular file.')
}
if (!stat.isSymbolicLink() && typeof process.getuid === 'function' && stat.uid !== process.getuid()) {
throw new Error('Desktop installation ID is owned by another user.')
}
fs.unlinkSync(filePath)
} catch (error: any) {
if (error?.code !== 'ENOENT') {
throw error
}
}
fs.writeFileSync(filePath, JSON.stringify({ installationId }), { encoding: 'utf8', flag: 'wx', mode: 0o600 })
return installationId
} finally {
if (repairFd !== undefined) {View on GitHub (pinned to c896c09c42)
Solutions
- Give the job a fresh future schedule in the same update: {'enabled': True, 'schedule': '1h'}.
- For a rerun, create a new one-shot job instead of reviving the expired one.
- Use resume_job for paused jobs — it raises the dedicated 'Cannot resume' error with clearer intent.
Example fix
# before
update_job(job_id, {"enabled": True}) # one-shot already expired
# after
update_job(job_id, {"enabled": True, "schedule": "30m"}) Defensive patterns
Strategy: try-catch
Validate before calling
from cron.jobs import load_jobs, compute_next_run
from datetime import datetime
def can_reenable(job: dict) -> bool:
if job["schedule"].get("kind") != "once":
return True
return compute_next_run(job["schedule"]) is not None # None = expired one-shot Try / catch
try:
update_job(job_id, {"enabled": True})
except ValueError as e:
if "grace window" in str(e): # expired one-shot re-enabled
update_job(job_id, {"enabled": True, "schedule": "1h"}) # fresh schedule too
raise Prevention
- Before bulk-enabling jobs, filter out expired one-shots or refresh their schedules in the same update.
- Use resume_job for pause/resume flows — its error message is the most actionable.
When it happens
Trigger: update_job(id, {'enabled': True}) or {'state': 'scheduled'} on a one-shot job whose run_at already passed while it was disabled/paused; clearing next_run_at via an update.
Common situations: Re-enabling an old one-shot job after its fire time; un-pausing via raw update instead of resume_job; bulk 'enable all' scripts that wake expired one-shots.
Related errors
- Could not generate a valid desktop installation ID.
- Timed out connecting to Hermes backend after ${timeoutMs}ms
- Desktop installation ID is owned by another user.
- Preview mode — launching is disabled.
- no install root
AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14).
Data as JSON: /api/errors/74824b0242ed4f4d.
Report an issue: GitHub.