NousResearch/hermes-agent · error

Could not repair the desktop installation ID.

Error message

Could not repair the desktop installation ID.

What it means

GatewayLifecycleBlocked from cron/lifecycle_guard.py:708: the job's prompt and/or script (including referenced script files) contains a gateway lifecycle command (e.g. `hermes gateway restart/stop`) or a persistent `launchctl submit` operation. Under launchd/systemd supervision, killing the gateway causes the supervisor to SIGTERM-respawn it in a loop — an agent could wedge the machine (#30719) — so creation/update of such cron jobs is blocked outright.

Source

Thrown at apps/desktop/electron/desktop-installation.ts:122

      }

      fs.writeFileSync(filePath, JSON.stringify({ installationId }), { encoding: 'utf8', flag: 'wx', mode: 0o600 })

      return installationId
    } finally {
      if (repairFd !== undefined) {
        fs.closeSync(repairFd)
      }

      try {
        fs.unlinkSync(repairPath)
      } catch {
        void 0
      }
    }
  }

  throw new Error('Could not repair the desktop installation ID.')
}

function sshOwnershipId(installationId, scope) {
  if (!INSTALLATION_ID_RE.test(String(installationId || ''))) {
    throw new Error('Desktop installation ID is invalid.')
  }

  return crypto
    .createHash('sha256')
    .update(`${installationId}\0${String(scope || '')}`)
    .digest('hex')
    .slice(0, 32)
}

export { INSTALLATION_ID_RE, loadOrCreateInstallationId, parseInstallationId, readInstallationId, sshOwnershipId }

View on GitHub (pinned to c896c09c42)

Solutions

  1. Remove `hermes gateway restart/stop` (and launchctl submit) from the job's prompt and any scripts it references.
  2. If a restart is genuinely needed, run `hermes gateway restart` from a shell OUTSIDE the running gateway, or via systemd `systemctl --user restart hermes-gateway` defined by the admin, not by a cron job.
  3. For config reload needs, check whether the gateway picks up config without a restart instead.

Example fix

# before
create_job(prompt="run `hermes gateway restart` to apply config", schedule="1d")

# after
# (no cron job) — from a user shell:
#   hermes gateway restart
Defensive patterns

Strategy: validation

Validate before calling

from cron.lifecycle_guard import contains_gateway_lifecycle_command_or_referenced_script

prompt = "nightly maintenance"
if contains_gateway_lifecycle_command_or_referenced_script(prompt, cwd=None):
    raise ValueError("refusing to create job: contains gateway lifecycle command")
create_job(prompt=prompt, schedule="1d")

Try / catch

from cron.lifecycle_guard import GatewayLifecycleBlocked
try:
    create_job(prompt=p, schedule="1d", script=s)
except GatewayLifecycleBlocked:
    # strip `hermes gateway restart/stop` / launchctl submit from prompt AND scripts, then retry;
    # if a restart is truly needed, do it from a user shell, not a cron job
    raise

Prevention

When it happens

Trigger: create_job whose prompt says 'run hermes gateway restart nightly', whose script invokes `hermes gateway stop/restart`, or whose prompt references a script file containing those strings (scripts are scanned too, non-regular/oversized script files fail closed via a sentinel).

Common situations: Trying to automate gateway restarts for config changes or memory leaks; an agent asked to 'keep the gateway healthy' choosing a cron restart; embedding lifecycle commands in a .py helper the job runs.

Related errors


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