Daemon self-respawn-on-upgrade can hit EACCES and orphan-reap all background workers

Status Open
Reported on v2.1.246
Maintainer reply None cached
Activity 0 comments · opened Aug 27, 2026

Summary

The Claude Code daemon's self-respawn-on-upgrade logic can hit EACCES when trying to posix_spawn the just-updated claude.exe binary, which kills the daemon and orphan-reaps all background (claude --bg) workers ~60s later. There's no retry, so a single unlucky timing window during an auto-update can take down every running background session.

Environment

  • OS: Windows 11 (build 10.0.26100) running WSL2, distro Ubuntu-24.04
  • Node: v22.17.0 via nvm
  • Claude Code: installed via npm i -g @anthropic-ai/claude-code, binary at ~/.nvm/versions/node/v22.17.0/lib/node_modules/@anthropic-ai/claude-code/bin/claude.exe
  • Version at time of incident: upgrading from 2.1.246

What happened (from ~/.claude/daemon.log)

[2026-08-27T02:04:03.608Z] [supervisor] binary at .../bin/claude.exe changed (mtime changed) — self-restarting for upgrade
[2026-08-27T02:04:03.611Z] [supervisor] shutting down (cause=upgrade, uptime=7897s, leases=0, live_workers=1)
[2026-08-27T02:04:13.670Z] [supervisor] upgrade self-respawn failed to spawn: EACCES: permission denied, posix_spawn '.../bin/claude.exe' — bg workers may be orphan-reaped ~60s after this process exits unless a client restarts the daemon (run `claude agents`)

Note the ~10s gap between detecting the mtime change and shutting down, then the respawn attempt at +10s failing with EACCES. By the time I checked (~8 hours later, ls -la on the binary), the file was a completely normal -rwxr-xr-x (755), fully executable — so this isn't a persistent permission problem, it's a transient one during the update window itself.

This repeated a second time a few minutes later on a freshly-restarted daemon:

[2026-08-27T02:18:29.312Z] [supervisor] ─── daemon start ─── version=2.1.246 pid=64602 origin=transient
...
[2026-08-27T02:19:29.401Z] [supervisor] binary at .../bin/claude.exe changed (mtime changed) — self-restarting for upgrade
[2026-08-27T02:19:29.406Z] [supervisor] shutting down (cause=upgrade, uptime=60s, leases=0, live_workers=1)
[2026-08-27T02:19:39.486Z] [supervisor] upgrade self-respawn failed to spawn: EACCES: permission denied, posix_spawn '.../bin/claude.exe'

Impact

I had a long-running claude --bg background session (an hourly polling automation) that got silently killed both times. Because the daemon itself had exited, claude agents --json no longer listed the session at all — nothing to inspect, no error surfaced to any client. It took several rounds of an external watchdog script re-launching claude --bg (each new session also dying quickly, presumably because the daemon/binary was still settling) before things stabilized, several hours later, only because I happened to have an unrelated always-on watchdog checking for staleness.

Without that external watchdog, this would have gone completely undetected — there's no user-facing signal that the daemon crashed mid-upgrade and took the background workers with it.

Suspected root cause

Looks like a race between whatever writes the new binary during auto-update (write content, then presumably chmod +x or similar to restore the executable bit) and the daemon's own mtime-change detection + immediate self-respawn. If the respawn attempt lands in the narrow window after the new content is written but before permissions/finalization complete, posix_spawn returns EACCES. A plain overwrite-in-place (rather than write-to-temp + atomic rename) would produce exactly this symptom.

Suggested fix

  • Retry the self-respawn a few times with a short backoff before giving up and orphan-reaping background workers, since the underlying binary is very likely to become spawnable within a second or two.
  • Or: make the updater write to a temp path and atomically rename() into place (with the executable bit already set) so the mtime-changed binary is always immediately spawnable the instant it's observable.
  • At minimum, surface something client-visible when this happens (a warning in claude agents, a log the next interactive session picks up on) rather than silently reaping background workers.

Reproduction

Not reliably reproducible on demand (timing-dependent on when an auto-update lands relative to the daemon's polling of the binary's mtime). Happened twice within 15 minutes for me on 2026-08-27 during what looks like two back-to-back version bumps.

View original on GitHub ↗