Skip to content

macOS launchd: gateway exits with EX_CONFIG (78) causing persistent spawn scheduled state #5589

@unw1red

Description

@unw1red

Environment

  • macOS 15.3 (Apple M4 Pro, 64GB)
  • Hermes: commit 6f1cb46
  • HERMES_HOME: /Volumes/McGwire/hermes (external volume)
  • Platforms: Discord + Home Assistant

Problem

After hermes gateway install, the launchd service enters a persistent spawn scheduled state with last exit code = 78: EX_CONFIG. The gateway does start, connect to Discord + HA, and run — but then exits after ~10-14 seconds with exit code 78 instead of running indefinitely.

Exit code 78 (EX_CONFIG from sysexits.h) tells macOS launchd to not auto-restart the job, leaving the service permanently stuck in spawn scheduled regardless of KeepAlive.SuccessfulExit = false.

Observations

  • Gateway runs fine in foreground (hermes gateway run) indefinitely
  • launchctl list | grep hermes shows: - 78 ai.hermes.gateway-011875d8
  • runs = N increments each restart cycle, confirming the gateway does start
  • The gateway logs show a clean startup (Discord + HA connected) followed by Stopping gateway... ~10s later
  • sys.exit(78) is not present anywhere in the Hermes codebase
  • Exit code 78 does NOT occur when killed via SIGTERM in foreground tests (exits with 0)
  • The issue persists across launchctl bootout + bootstrap cycles
  • A competing older plist (ai.hermes.gateway.plist with different HERMES_HOME) was also present — removing it did not resolve the issue

launchctl print output (relevant excerpt)

state = spawn scheduled
minimum runtime = 10
exit timeout = 5
runs = 10
last exit code = 78: EX_CONFIG
immediate reason = semaphore
semaphores = {
    successful exit => 0
}

Workaround

Running hermes gateway run manually in a launchctl kickstart after each macOS login. A watchdog-style plist that just calls hermes gateway start on an interval would also work.

Request

  1. Identify what causes the Python process to exit with code 78 specifically under launchd (vs foreground)
  2. Consider adding ThrottleInterval back to the plist template and/or using exit code 1 consistently so launchd's KeepAlive policy can manage restarts correctly

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium — degraded but workaround existscomp/cliCLI entry point, hermes_cli/, setup wizardcomp/gatewayGateway runner, session dispatch, deliverytype/bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions