claude-code - 💡(How to fix) Fix claude --bg daemon idle-exit (5s) races client handshake → "socket missing"

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Error Message

Most of the time it works. Occasionally the second call races the supervisor's idle-exit and prints the socket-missing error. Our daemon log on a failing call shows:

Fix Action

Fix / Workaround

Attempted workarounds that don't work

The only locally-reliable workaround we've found is a continuous heartbeat loop (while true; do claude agents; sleep 3; done) wrapping the --bg call to guarantee a client is always within the 5s idle window. That's wasteful and shouldn't be necessary.

Happy to test patches.

Code Example

Starting background service…
Couldn't reach the background service (socket missing) — run 'claude daemon status'

---

[supervisor] idle 5s with no clients — exiting

---

[2026-05-29T07:40:39.563Z] [supervisor] ─── daemon start ─── pid=2454855 origin=transient
[2026-05-29T07:40:39.616Z] [supervisor] workers=0
[2026-05-29T07:40:39.658Z] [bg] bg adopt: adopted=0 dead=1
[2026-05-29T07:40:44.620Z] [supervisor] idle 5s with no clients — exiting
[2026-05-29T07:40:44.622Z] [supervisor] shutting down
[2026-05-29T07:40:44.987Z] [supervisor] ─── daemon start ─── pid=2454889 origin=transient
[2026-05-29T07:40:45.038Z] [supervisor] workers=0
[2026-05-29T07:40:50.042Z] [supervisor] idle 5s with no clients — exiting
RAW_BUFFERClick to expand / collapse

Version: Claude Code 2.1.139 + 2.1.150 · Linux (Ubuntu, Hetzner) · Node v22

What I expected

claude --bg "<prompt>" invoked from a long-quiet shell (e.g. a systemd timer firing every 6h) reliably spawns a background session and prints backgrounded · <short_id>, even when the supervisor daemon is not currently running.

What actually happens

When the daemon is cold or has just idle-exited, claude --bg occasionally exits non-zero with:

Starting background service…
Couldn't reach the background service (socket missing) — run 'claude daemon status'

No session ID is emitted. Subsequent calls within a few seconds usually succeed.

Reproduction

  1. claude --bg "<any prompt>" to start the daemon, let it spawn the session.
  2. Wait until the daemon idle-exits (≈5s after the last client disconnects). Confirm in ~/.claude/daemon.log:
    [supervisor] idle 5s with no clients — exiting
  3. Fire another claude --bg "<prompt>".

Most of the time it works. Occasionally the second call races the supervisor's idle-exit and prints the socket-missing error. Our daemon log on a failing call shows:

[2026-05-29T07:40:39.563Z] [supervisor] ─── daemon start ─── pid=2454855 origin=transient
[2026-05-29T07:40:39.616Z] [supervisor] workers=0
[2026-05-29T07:40:39.658Z] [bg] bg adopt: adopted=0 dead=1
[2026-05-29T07:40:44.620Z] [supervisor] idle 5s with no clients — exiting
[2026-05-29T07:40:44.622Z] [supervisor] shutting down
[2026-05-29T07:40:44.987Z] [supervisor] ─── daemon start ─── pid=2454889 origin=transient
[2026-05-29T07:40:45.038Z] [supervisor] workers=0
[2026-05-29T07:40:50.042Z] [supervisor] idle 5s with no clients — exiting

So the supervisor started twice and idle-exited twice within 11s — the CLI client never managed to connect/handshake before each fresh daemon exited.

Impact

We run claude --bg from a systemd timer every 6h to fire an autonomous agent. The race hits about 1 cron tick per 24h, dropping the agent for that 6h window. The next cycle works fine.

Attempted workarounds that don't work

  1. Retry on failure — masks intermittent failure but does not address the race.
  2. claude agents >/dev/null warm-up immediately before claude --bg — only works when the gap between the two calls stays under the 5s idle window. When system load grows the gap past 5s, the warmed daemon idle-exits before --bg can connect and the race re-fires anyway. Tested and reverted.
  3. claude daemon logs — does not hold an open client connection; just streams the log file and exits.

The only locally-reliable workaround we've found is a continuous heartbeat loop (while true; do claude agents; sleep 3; done) wrapping the --bg call to guarantee a client is always within the 5s idle window. That's wasteful and shouldn't be necessary.

Suggested upstream fix directions

Any one of these would close the race:

  1. Lengthen / configurable daemon idle timeout. 5s is aggressive for a daemon that's expected to handle on-demand spawns from cold. A 30s default plus a --json-path config knob (idle_timeout_ms) would eliminate the race in practice.
  2. Delay idle-exit until the spawning client has handshaken at least once. When the CLI forks the daemon, it intends to immediately connect — the supervisor could wait for that initial client before starting its idle countdown.
  3. CLI-side retry on EAGAIN/socket-missing. When the CLI sees a missing/closed socket immediately after the daemon-start call it issued, retry the connect with a short backoff. Already-correct semantics for the same-process spawn case.

Happy to test patches.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

claude-code - 💡(How to fix) Fix claude --bg daemon idle-exit (5s) races client handshake → "socket missing"