[BUG] macOS: silently-denied Local Network permission permanently breaks all daemon-spawned sessions (ENOTFOUND); attaching to a fleet session poisons every session in the terminal
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
Environment
- Claude Code 2.1.217 (native installer, auto-updating), macOS 26 (Darwin 25.5.0)
- Home network where the only DNS resolver is the router itself (Fritz!Box at 192.168.178.1 — a local-network address). This is the default on very common consumer routers.
What's wrong
Every daemon-spawned session (resumed from the agent overview / FleetView, pre-warmed spares, background handoffs) fails every API call with API Error: Unable to connect to API (ENOTFOUND), while directly-spawned terminal sessions work fine. Deterministic repro for a week, across 2.1.215→2.1.217.
Root cause, confirmed by decoding /Library/Preferences/com.apple.networkextension.plist:
- The identity
com.anthropic.claude-codehas a macOS Local Network record withDenyMulticast=True, MulticastPreferenceSet=False— i.e. a default-deny minted without the permission prompt ever being shown. - It was minted when the daemon/spare architecture first ran on this machine (~Jul 16, arriving via auto-update) while the user was working over SSH/screen-share. Daemon workers are TCC-disclaimed background processes (
CLAUDE_BG_TCC_DISCLAIMED=1) with no UI, so macOS could never display the one-time prompt → silent default-deny, permanent. - Denied workers cannot resolve any hostname when DNS goes through mDNSResponder. Notably, configuring public resolvers (1.1.1.1) does not help — resolution is blocked at the mDNSResponder policy layer for these processes regardless of resolver address (consistent with the "Failed to create Attribution Chain" behavior in #59065).
- Directly-spawned
claudeis attributed to the terminal app (not gated) → works. This made the failure look random (and made--debuglook like a fix, since debugging always happened in fresh foreground processes).
The "poisoning" behavior (worst part UX-wise)
- Fresh terminal, plain
claude→ in-process session → works. - Open the agent overview and select any older session → the daemon claims a spare and hosts it (
daemon.log: bg claimed-spare <id> (fleet)) → ENOTFOUND. - The user's original working session is simultaneously handed off to the daemon (so it can keep running in the background), and any new session created afterwards is also daemon-spawned. From that moment every session in the terminal fails until the terminal is quit and Claude restarted.
So one visit to the agent overview converts a fully-working terminal into one where nothing can reach the API — with no hint why.
Why the user cannot fix it
- The denied identity is invisible in System Settings → Privacy & Security → Local Network (the pane only lists identities with
MulticastPreferenceSet=True; the "Claude" entry there is the desktop app). - macOS never re-prompts once a record exists; GUI-launching the app bundle triggers no prompt.
- The plist is entitlement-gated like TCC.db: direct write as root →
EPERM;sudo defaults importsilently mis-scopes to root's per-user domain; a properly-scopedCFPreferencesSetValue/Synchronize(kCFPreferencesAnyUser/AnyHost) returns success but cfprefsd silently drops the write. Short of Recovery-mode SIP-off, the deny record is immutable. - The Local Network entitlement added in 2.1.198 enables the prompt for fresh installs, but cannot heal a pre-existing deny record.
Workaround that fixed it
Pinning the API host in /etc/hosts (160.79.104.10 api.anthropic.com): hosts entries are resolved in-process by libinfo, bypassing mDNSResponder's policy denial, and the Local Network gate doesn't block TCP to public IPs. All daemon-spawned sessions immediately started working, deny record still in place. Downside: hardcoded IP, no failover, goes stale silently.
Suggested fixes
- Detect this state: if a daemon worker gets ENOTFOUND while a directly-spawned probe (or the parent terminal process) can resolve, surface a diagnostic pointing at the Local Network permission instead of a bare
API Error. claude doctorcould decode the networkextension records forcom.anthropic.claude-codeand flagDenyMulticast=True, MulticastPreferenceSet=Falseexplicitly.- Consider having daemon workers fall back to a non-mDNSResponder resolution path (or to the responsible-process attribution of the launching terminal) when resolution is policy-denied.
Related
- #59065 (bg-pty-host workers blocked by macOS TCC attribution failure)
- #27828 (CLI Local Network issues)
- Changelog 2.1.198 ("Fixed no route to host for local-network hosts in macOS background agent sessions by declaring Local Network entitlements")
What Should Happen?
Daemon-spawned sessions (fleet resume, spares, background handoffs) should have the same network access as directly-spawned terminal sessions. If macOS has silently default-denied the Local Network permission for com.anthropic.claude-code, Claude Code should detect it and tell the user what is wrong (e.g. in claude doctor and instead of the bare API Error: Unable to connect to API (ENOTFOUND)), rather than failing opaquely in only some session types. Attaching to a session from the agent overview should also never degrade the sessions the user subsequently starts in that terminal.
Error Messages/Logs
UI (every daemon-spawned session, on every message):
API Error: Unable to connect to API (ENOTFOUND)
Unable to connect to API (ENOTFOUND) · Retrying in 3s · attempt 4/10
(also shows "✗ Auto-update failed · Run claude doctor" — same root cause, the worker cannot resolve any hostname)
~/.claude/daemon.log at the moment old sessions were resumed from the agent overview (all failed with ENOTFOUND):
[2026-07-22T06:25:39.169Z] [bg] bg claimed-spare 4d186336 (fleet)
[2026-07-22T06:28:24.369Z] [bg] bg claimed-spare 15a85be4 (fleet)
Deny record in /Library/Preferences/com.apple.networkextension.plist:
com.anthropic.claude-code | DenyMulticast = True | MulticastPreferenceSet = False <- prompt never shown
com.anthropic.claudefordesktop | DenyMulticast = False | MulticastPreferenceSet = True
Also in daemon.log (separate latent issue):
[supervisor] auth: headless daemon cannot complete OAuth — run `claude auth login` to refresh
[supervisor] auth: no token found, will re-check keychain every 30s
Steps to Reproduce
Preconditions: macOS machine whose DNS resolver is the router itself (e.g. default Fritz!Box setup: resolver = 192.168.178.1, a local-network address).
- Get macOS to mint a default-deny Local Network record for
com.anthropic.claude-code. This happens by itself if the daemon/spare architecture's first-ever worker touches the network while nobody can answer the permission prompt — in our case the daemon first ran (arriving via auto-update) while the user was connected over SSH/screen-share. Disclaimed background workers can never display the prompt, so the deny is minted silently. Result:DenyMulticast=True, MulticastPreferenceSet=Falsein /Library/Preferences/com.apple.networkextension.plist. - Open a fresh terminal, run plain
claude, send a message → works (in-process session, attributed to the terminal app). - Open the agent overview and select any past session → every message fails with
API Error: Unable to connect to API (ENOTFOUND)(daemon claims a spare:bg claimed-spare <id> (fleet)in daemon.log). - Switch back to the original session, or create a new one from the overview → these now fail with ENOTFOUND too (original session was handed off to the daemon; new sessions are daemon-spawned).
- Quit the terminal, relaunch, plain
claude→ works again — until step 3 is repeated. 100% reproducible.
Confirmed the mechanism by running the same session both ways: identical session resumed via the overview fails; after pinning api.anthropic.com in /etc/hosts (bypassing mDNSResponder), the same daemon-hosted sessions work with the deny record still in place.
Claude Model
None
Is this a regression?
Yes, this worked in a previous version
Last Working Version
2.1.214 (last version before the daemon/spare architecture first ran on this machine, Jul 16)
Claude Code Version
2.1.217 (Claude Code)
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Terminal.app (macOS)
Additional Information
_No response_
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗