[Tahoe 26.x] terminal process tree EPERM in ~/Documents — root cause analysis & data
TL;DR
On macOS Tahoe 26.3, Claude Code sessions running inside a terminal (originally iTerm, later switched to Ghostty — both affected) intermittently trigger Operation not permitted for any read/exec under ~/Documents, across every shell in that terminal's process tree. cmd+Q + restart reliably recovers; no in-place fix works.
Over ~6 days I've collected 5 incidents and tested 4 hypotheses to refute. I'm filing this primarily to share refuted hypotheses so others don't redo the work, and to ask what additional data Anthropic / community would find useful.
Environment
- macOS 26.3 (Tahoe, build 25D125)
- Claude Code 2.1.139 (auto-update enabled)
- Terminal: Ghostty 1.3.1 (after migrating from iTerm2 stable — both exhibit the issue)
- Shell: zsh 5.9 (
/bin/zshsystem default) - FDA grants in place: iTerm, Ghostty,
claude.exe(added manually after first major incident) - Other relevant: company-issued machine with EndpointProtector DLP (CoSoSys) — but colleagues with same DLP + Claude Code don't see this, so DLP is not the sole cause
Symptoms
Same as #49820 / #21942 / #21654:
git,bash <script>,cat <file>,ls <dir>all returnOperation not permittedfor any pre-existing file under~/Documents- Only inside the affected terminal's process tree — opening a fresh terminal of a different app is fine
~/Desktop,~/Downloads,/tmpunaffected even during incident- Fresh-write into
~/Documentssucceeds, and fresh-exec of newly-written files succeeds — only pre-existing files are denied (this last point conflicts with the simple "kernel taints the tree" mental model) - No TCC prompt; no entry in
log show --predicate 'subsystem == "com.apple.TCC"'corresponding to the deny - cmd+Q the whole terminal app + restart → fully recovers
- Recurrence interval: 1-4 days, no obvious trigger from user side
Reproduction
I don't have a clean repro recipe. The trigger appears non-deterministic. One distinctive observation from the most recent incident: claude.exe directory was rewritten (mtime of every file under /opt/homebrew/lib/node_modules/@anthropic-ai/claude-code/ updated within minutes of incident detection) without any npm install log → presumably Claude Code's built-in self-updater. The timing correlation is suggestive but not proven causal.
Hypotheses tested and refuted
I want to surface these so others can skip them.
❌ H1: claude.exe missing TCC entry → terminal tree gets tainted ("guilt by hosting")
- Initial hypothesis after first deep incident
- Adding
/opt/homebrew/lib/node_modules/@anthropic-ai/claude-code/bin/claude.exeto FDA gave 4 days of no recurrence → seemed confirmed - Refuted day 5: FDA entry still in system TCC.db (
SELECT auth_value FROM access WHERE client LIKE '%claude%.exe%'returns2), incident recurred with identical symptoms
❌ H2: TCC entry binds CDHash, gets invalidated on update
- Hypothesized after H1 refute: maybe npm/self-update changes CDHash and breaks entry
- Decoded
csreqblob in/Library/Application Support/com.apple.TCC/TCC.db: it'sidentifier "com.anthropic.claude-code" and anchor apple generic and certificate leaf[subject.OU] = "Q6L2SF6YDW"— identifier + Team ID binding, not CDHash - New binary still matches the requirement
- Refuted: csreq is content-agnostic w.r.t. CDHash; npm updates don't invalidate the entry
❌ H3: Tahoe AllFiles no longer auto-subsumes DocumentsFolder
- Ghostty has
kTCCServiceSystemPolicyAllFiles=allowin system TCC.db but no explicitkTCCServiceSystemPolicyDocumentsFolderentry - iTerm has both explicitly
- Theory: Tahoe split the supersede relationship
- Refuted: System Settings → Privacy → Files and Folders shows Ghostty with "Full Disk Access" tag (locked, inherited from FDA setting), confirming AllFiles still subsumes Documents
❌ H4: DLP / EndpointSecurity extension is the gatekeeper
- Reported
EndpointProtectorClientinFiles and Folderspermission list - Theory: third-party DLP hooking file ops below TCC layer (which would explain why TCC logs show no deny)
- Refuted: Colleagues with the same DLP + Claude Code combo don't see this
Surviving but unprovable hypotheses
- H5:
claude.exeis not the responsible subject at all — H1's 4-day stability was coincidental. No clear path to falsify without an A/B comparison. - H6: Another macOS layer (CoreServices? launchd-tracked file attribution?) is gatekeeping.
systemextensionsctl listshows only Fortinet VPN; no Endpoint Security extensions present. - H7 (weak): Claude Code's silent self-updater rewrites the binary directory, which invalidates some per-inode kernel cache, which re-evaluates incorrectly under Tahoe. Time-line evidence only; no proof.
Workarounds tried
| Workaround | Effect | Cost |
|---|---|---|
| cmd+Q + restart terminal app | Reliable | Lose unsaved session state |
| Add claude.exe to FDA | Helped initially, recurred after 4 days | Manual repeat after each update? unclear |
| Switch terminal (iTerm → Ghostty) | No effect (both fail) | One-time migration |
| Force bash via CLAUDE_CODE_SHELL=/bin/bash | Reported elsewhere; haven't tried | Lose zsh |
| Disable Claude Code auto-update | Untested but planned | Manual updates required |
Diagnostic data collected
I've kept structured logs of each incident in a local repo: process chain dumps, TCC.db state snapshots, log show excerpts, xattr traces, fresh-exec boundary tests. Happy to share specific excerpts on request — I can post sanitized snippets here if there's interest, or attach a .tar.gz.
Particularly distinctive on the most recent incident: TCC log over 30 minutes around the incident contains zero denies for claude.exe or ~/Documents access — contradicting the assumption that this is a TCC-layer denial.
Asks for maintainers
- What additional data would help you root-cause this? I'm willing to instrument further.
- Is the silent self-updater documented anywhere? I want to be sure it's not coincidental that
claude.exe's mtime gets rewritten withoutnpm installlogs. - Can
claudeship with a--disable-autoupdaterorautoUpdates: falseconfig that's discoverable inclaude doctor? I'd opt in if I knew it existed. - Is anyone tracking this against Apple Feedback Assistant? If the root cause is Tahoe-side, this might need parallel reporting.
Related issues
- #49820 — Tahoe zsh sysctl sandbox
- #21942 — com.apple.provenance
- #21654 — cwd-* op not permitted
- #22109 — zsh writes to /tmp/claude-501
- #22008 — hooks ignored on iTerm
All overlap in symptom but none isolate the root cause.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗