Skip to main content
← Back to list
01Issue
BugOpenSwamp CLITeam
AssigneesNone

Relationships

#1414 worker daemon enable: relative/missing --cache-dir fails launchd EX_CONFIG while daemon status reports running

Opened by magistr · 7/26/2026

swamp worker daemon enable writes the --cache-dir value verbatim into the generated service definition's WorkingDirectory and never creates the directory. Two consequences, both silent:

  1. A relative --cache-dir produces a relative WorkingDirectory, which launchd rejects.
  2. An absolute but non-existent --cache-dir fails the same way.

In both cases the job never runs (last exit code = 78: EX_CONFIG), the worker never enrolls — and swamp worker daemon status --user still reports running / Enabled: yes, so the operator has no signal that anything is wrong.

Reproduce (macOS, swamp 20260725.011748.0-sha.bb2cb3ef)

swamp worker daemon enable ws://127.0.0.1:9321 --user \
  --token <enroll>.<secret> --server-token <admin>.<secret> \
  --cache-dir ./daemon-cache --label spike=1

swamp worker daemon status --user
#   Status (user service): running
#   Enabled: yes

launchctl print gui/$(id -u)/club.swamp.worker
#   state = spawn scheduled
#   last exit code = 78: EX_CONFIG

swamp worker list --server ws://127.0.0.1:9321 --token <admin>.<secret>
#   {"workers": [], "count": 0}

The generated ~/Library/LaunchAgents/club.swamp.worker.plist contains:

<key>WorkingDirectory</key>
<string>./daemon-cache</string>

Passing an absolute path whose directory does not yet exist fails identically. Creating the directory first and re-running enable (or launchctl kickstart) makes the worker enroll normally — confirming the path handling is the only fault.

Expected

Any of, in rough order of preference:

  • enable creates the cache directory (it already owns the machine-id file that lives there);
  • enable resolves --cache-dir to an absolute path before writing the service definition, and rejects a path it cannot create with an actionable error;
  • daemon status reports the real launchd/systemd job state (including last exit code) rather than "running" for a job that is only scheduled to spawn.

The last point is the one that costs the most debugging time: status actively contradicts the failure, so the natural next step (check the worker list, find nothing, suspect enrollment or tokens) leads away from the actual cause.

Notes

Found while building an agent-driven client that installs the managed worker daemon on a customer's machine; the client now absolutizes and mkdir -ps the cache directory before calling enable, which is a reliable workaround. Tokens are handled well otherwise — they go into the service definition's EnvironmentVariables at mode 0600, never on argv.

02Bog Flow
OPENTRIAGEDIN PROGRESSSHIPPED

Open

7/26/2026, 11:20:43 AM

No activity in this phase yet.

03Sludge Pulse

Sign in to post a ripple.