[BUG] bg-pty-host children blocked by macOS TCC on \~/Documents despite FDA grant — "Failed to create Attribution Chain"

Resolved 💬 2 comments Opened May 14, 2026 by ajiblock Closed May 16, 2026

Preflight Checklist

  • [x] I have searched existing issues — closest is #58353 (bg agents don't load Claude.ai remote connectors). Same architectural area (bg-spawned children failing to inherit something from the interactive session), but a different surface (filesystem TCC vs. MCP loader). Not a duplicate.
  • [x] This is a single bug report
  • [x] I am using the latest version of Claude Code (2.1.141)

Environment

  • Claude Code: 2.1.141 (npm install: /opt/homebrew/lib/node_modules/@anthropic-ai/claude-code/bin/claude.exe)
  • macOS: 26.3.1 (Tahoe), build 25D771280a, Darwin 25.3.0, arm64
  • Shell: zsh, terminal Ghostty
  • Codesign: Identifier=com.anthropic.claude-code, TeamIdentifier=Q6L2SF6YDW, Developer ID signed, hardened runtime
  • Project location: ~/Documents/claude/<project> (any project under ~/Documents)

What's wrong

Background-job sessions spawned by claude.exe --bg-pty-host (i.e. anything reached via the bg-job runtime — claude --bg ..., Agent fan-out, /loop, scheduled-from-cli, etc.) cannot read or list files under ~/Documents on macOS, even though Full Disk Access is properly granted to com.anthropic.claude-code in the user's TCC database.

Foreground claude sessions launched directly from a terminal (Ghostty, Terminal.app, iTerm) work fine — the same binary, same FDA grant, same target paths. The break is specific to the bg-spawned path.

Symptom for the user: every Read, ls, cat, find, etc. against a ~/Documents/... path returns Operation not permitted / EPERM. The harness misreports it as "Working directory was deleted" and recovers cwd to $HOME. Writes via Edit/Write tools fail with EPERM. Newly-created files in the same dir sometimes succeed transiently while ambient terminal focus is on the path; reads of existing files don't.

Root cause (with evidence)

The sandboxd log for the denied request:

sandboxd: (TCC) [com.apple.TCC:access] SEND ... function=TCCAccessRequest,
  service=kTCCServiceSystemPolicyDocumentsFolder
sandboxd: tcc_server_message_request_authorization(kTCCServiceSystemPolicyDocumentsFolder) failed:
  Error Domain=kTCCErrorDomain Code=5
  "server error: Failed to create Attribution Chain from message."

So the failure isn't a policy denial — the kernel can't construct a responsible-app attribution chain for the bg-spawned process at all, so the TCC policy table is never consulted. Default = deny.

Why the chain fails for this process:

$ ps -eo pid,ppid,etime,command | grep claude.exe
85249     1   37:18  claude.exe --bg-pty-host ...  --  claude.exe --bg-spare ...
85250 85249  37:18  claude.exe --bg-spare ...
99030 85250 ...     /bin/zsh (my shell)

PPID of the bg-pty-host is 1 (launchd) — the bg-pty-host was daemonized and reparented to launchd before forking the bg-spare child. From the bg-spare's perspective there is no foreground app in the parent chain.

$ lsappinfo info -only responsiblepid $$
"responsiblepid"=[ NULL ]

No responsible PID is set on the spawned shell. There's no responsibility init on the bg-pty-host or on the bg-spare to register com.anthropic.claude-code (or claude-code itself) as the responsible application for descendants. Without that, sandboxd's attribution chain dead-ends at launchd.

By contrast, a foreground claude started from Ghostty inherits Ghostty as the responsible app — Ghostty has FDA in its own right, so the chain succeeds and the eventual TCC consult lands on the granted-since-April com.anthropic.claude-code bundle ID entry.

TCC.db state — FDA is granted

From ~/Library/Application Support/com.apple.TCC/TCC.db:

kTCCServiceSystemPolicyDocumentsFolder | com.anthropic.claude-code | client_type=0 (bundleid) | auth_value=2 (allowed) | 2026-04-14
kTCCServiceSystemPolicyDesktopFolder   | com.anthropic.claude-code | client_type=0 (bundleid) | auth_value=2 (allowed) | 2026-04-14
kTCCServiceSystemPolicyDownloadsFolder | com.anthropic.claude-code | client_type=0 (bundleid) | auth_value=2 (allowed) | 2026-04-15

This grant correctly applies to all binaries codesigned with Identifier=com.anthropic.claude-code — including the running 2.1.141 npm binary. It works in foreground; the bg path never reaches it because of the attribution-chain failure.

Reproduction

  1. macOS 26.x (Tahoe), claude-code 2.1.141, project under ~/Documents/....
  2. Confirm FDA is granted to com.anthropic.claude-code (or to the claude entry in System Settings → Privacy & Security → Full Disk Access).
  3. From any interactive claude session, spawn a bg job that needs to read ~/Documents/<anything>/<file>.
  4. The bg job hits EPERM on every read/list against ~/Documents/**.
  5. The sandboxd log shows the "Failed to create Attribution Chain" error at the same timestamp.

Suggested fix

claude.exe --bg-pty-host (and/or --bg-spare) should establish a proper responsibility before forking children, so that sandboxd can attribute their syscalls back to a known app and reach the bundle-ID-keyed FDA grant. macOS exposes this via responsibility_spawnattrs_setdisclaim() / posix_spawnattr_setflags(..., POSIX_SPAWN_SETDISCLAIM) from <spawn.h>, or by ensuring the daemon publishes itself via LSRegisterURL-equivalent so its codesign identity surfaces as the responsible app.

Alternately, the bg daemons could be launched via posix_spawn with RESPONSIBLE_PID set explicitly to the daemon's own PID before reparenting to launchd, so descendants inherit a non-NULL responsibility.

Workarounds I'm using

  • Run the task in a foreground claude session (works).
  • Move the affected project out of ~/Documents (TCC-protected dirs are only ~/Documents, ~/Desktop, ~/Downloads; anywhere else under ~ is unrestricted).
  • Pin @anthropic-ai/claude-code to a previous version that didn't ship the bg-pty-host runtime, if that's relevant for your release timeline.

Why this is new for users

Until the bg-jobs runtime existed in Claude Code, every session ran as a child of an interactive terminal app (Ghostty / Terminal / iTerm) that already had FDA. Attribution flowed through that terminal app. With the bg daemon path, that's no longer true, and the TCC grant on com.anthropic.claude-code becomes unreachable for sandboxed file ops.

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗