Background daemon fails to auto-spawn on macOS — 'Could not switch to audit session: Operation not permitted' — agent view stuck on 'Opening…'

Open 💬 0 comments Opened Jul 1, 2026 by firat-elbey

Background daemon fails to auto-spawn on macOS — "Could not switch to audit session: Operation not permitted" — agent view stuck on "Opening…"

Summary

On macOS, the on-demand background daemon (supervisor) fails to auto-spawn. The transient/detached spawn crashes immediately with:

Could not switch to audit session 0x18700: 1: Operation not permitted

With no daemon running, the agent view (claude agents) can still list sessions (they're read from on-disk state), but opening any session hangs forever on "Opening…", because attaching a session requires the daemon and there is none.

The supervisor itself is healthy: running it in the foreground with claude daemon run works perfectly. Only the auto-spawn / daemonize path is broken. Since "Service install is disabled in this version — the daemon runs on demand," there is no LaunchAgent fallback, so the broken on-demand spawn leaves the feature completely unusable.

Environment

  • Claude Code: 2.1.198 (native build, ~/.local/share/claude/versions/2.1.198)
  • OS: macOS (Darwin 24.5.0)
  • Trigger: appeared immediately after the 2.1.197 → 2.1.198 auto-upgrade

Impact

Agent view is unusable — every "Open session" hangs on "Opening…". Relaunching Claude does not help, because relaunch re-triggers the same broken auto-spawn.

Steps to reproduce

  1. On 2.1.198 (macOS), with no daemon currently running.
  2. Open the agent view (claude agents) and select any session to open it — OR dispatch any background job (claude --bg "<task>"), which also triggers the daemon.
  3. Observe.

Actual behavior

  • The client prints Starting background service… then Couldn't reach the background service (not running) — run 'claude daemon status'.
  • No daemon process starts; ~/.claude/daemon.log gains no new ─── daemon start ─── line.
  • The control socket is never created:

``
control.sock: unreachable (connect ENOENT /tmp/cc-daemon-501/<id>/control.sock)
roster.json: absent
``

  • With --debug-file, the real crash is captured:

``
[ERROR] daemon: transient spawn stderr:
Could not switch to audit session 0x18700: 1: Operation not permitted
``

  • In the agent view specifically, sessions list fine but each "Open" sits at firstTerminalAt: null / "tempo":"blocked" indefinitely → "Opening…".

Expected behavior

The daemon auto-spawns on demand (as it did on 2.1.195–2.1.197), binds the control socket, and the agent view attaches the selected session.

Diagnosis (root cause localized)

The failure is isolated to the detach/daemonize step, not the supervisor:

| Path | Result |
|------|--------|
| Transient auto-spawn (double-fork + detach) | ❌ fails — Could not switch to audit session … Operation not permitted |
| claude daemon run (foreground supervisor, no daemonize) | ✅ starts clean, binds socket, creates roster |
| Sandbox on vs off | identical failure — not the sandbox |

Could not switch to audit session … Operation not permitted is the macOS symptom of a process attempting an audit-session switch from a context without an appropriate session (commonly a non-login context — tmux/screen, SSH, IDE-integrated terminal, or a process not attached to a login session). The daemonize path in 2.1.198 appears to perform (or newly trip) this audit-session switch and dies when it's denied.

Notably, the transition was visible in the log: the 2.1.197 daemon shut down for the upgrade —

[supervisor] binary changed (2.1.197 → 2.1.198) — self-restarting for upgrade
[supervisor] shutting down (cause=upgrade, …)

— and the 2.1.198 replacement never came back up, with every subsequent transient spawn failing as above.

Workaround

Run the supervisor in the foreground and leave it open:

claude daemon run     # keep this terminal open; daemon stays reachable

Then claude agents (in another terminal) connects to it and opens sessions normally. Launching from a plain login Terminal window (not tmux/SSH/IDE) may also let the auto-spawn succeed.

Suggested fixes

  • The daemonize path shouldn't hard-fail on an audit-session switch — treat setaudit/audit-session errors as non-fatal (skip the switch) rather than crashing the spawn.
  • Surface the transient-spawn stderr to the user (it's only visible via --debug-file today), so "Couldn't reach the background service" isn't a dead end.

View original on GitHub ↗