[BUG] macOS sandbox blocks `bind()` on Unix domain sockets for child processes, breaking `dotnet build` parallelism
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?
On macOS, the sandbox blocks bind() on Unix domain sockets for processes spawned via Process.Start() (child/grandchild processes). This breaks any tool that uses named pipes for inter-process communication, including dotnet build which uses MSBuild out-of-process worker nodes.
The sandbox settings allowAllUnixSockets, allowLocalBinding, enableWeakerNestedSandbox, and enableWeakerNetworkIsolation do not resolve this.
What Should Happen?
Steps to reproduce
- Enable the sandbox in
~/.claude/settings.json:
``json``
{
"sandbox": {
"enabled": true,
"autoAllowBashIfSandboxed": true,
"network": {
"allowAllUnixSockets": true,
"allowLocalBinding": true
}
}
}
- Create a solution with at least 2 projects (a library and a dependency), so MSBuild spawns worker nodes.
- Run
dotnet buildvia the Bash tool (without-maxcpucount:1).
Expected behavior
Build completes using parallel MSBuild nodes (takes ~1 second).
Actual behavior
Build hangs for exactly 5 minutes (MSBuild's default node connection timeout), then fails with 0 errors. MSBuild writes failure files to $TMPDIR/MSBuildTemp/ with this stack trace:
System.Net.Sockets.SocketException (13): Permission denied
at System.Net.Sockets.Socket.DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress)
at System.Net.Sockets.Socket.Bind(EndPoint localEP)
at System.IO.Pipes.NamedPipeServerStream.SharedServer..ctor(String path, ...)
at Microsoft.Build.BackEnd.NodeEndpointOutOfProcBase.InternalConstruct(String pipeName)
at Microsoft.Build.Execution.OutOfProcNode.Run(...)
MSBuild spawns worker node child processes. These child processes try to create a NamedPipeServerStream, which on macOS calls bind() on a Unix domain socket. The sandbox blocks this bind() call with EACCES (errno 13). The parent MSBuild process waits for the worker to connect (which never happens), hanging for the full 5-minute timeout.
Key diagnostic finding
A direct .NET process CAN create named pipes inside the sandbox:
// This WORKS when run directly via `dotnet run`
using var server = new NamedPipeServerStream("test", PipeDirection.InOut, 1,
PipeTransmissionMode.Byte, PipeOptions.Asynchronous | PipeOptions.CurrentUserOnly, 0, 0);
But when that same process spawns a child via Process.Start(), the child process CANNOT create named pipes — the bind() call fails with Permission denied. This confirms the sandbox applies different restrictions to descendant processes than to the direct process.
A Python test also confirms direct socket.bind() on AF_UNIX works in the sandbox — the restriction is specific to child processes.
Suggested fix
The macOS sandbox profile should allow bind() on AF_UNIX sockets when allowAllUnixSockets: true is set, including for descendant processes — not just the direct child of the sandboxed shell. This is needed by any tool that uses named pipes for IPC between parent and child processes (MSBuild, Roslyn VBCSCompiler, and likely other build systems).
Settings that were tested (none fixed the issue)
| Setting | Effect |
|---|---|
| allowAllUnixSockets: true | No effect on child process bind() |
| allowLocalBinding: true | No effect on child process bind() |
| allowUnixSockets: ["/tmp/claude/", ...] | No effect |
| enableWeakerNestedSandbox: true | No effect |
| enableWeakerNetworkIsolation: true | No effect |
| ignoreViolations: {"network-bind": ["*"]} | Only suppresses logging, doesn't allow the operation |
Workaround
Use excludedCommands: ["dotnet build:*", "dotnet test:*"] to run dotnet commands outside the sandbox. This defeats the purpose of sandboxing.
Alternatively, force single-node builds with dotnet build -maxcpucount:1, which avoids spawning child processes but loses multi-project parallelism.
Additional Information
Environment
Claude Model
Opus
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.84 (Claude Code)
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
iTerm2
Related issues
Several existing issues describe related sandbox problems, but none address this specific child-process bind() restriction:
Most closely related
- #28954 —
enableWeakerNetworkIsolationnot wired from settings to sandbox-runtime config (closed as duplicate of #26466). Same architectural pattern: a sandbox setting exists in the schema but is never translated into the actual macOS Seatbelt profile. Our issue likely has the same root cause —allowAllUnixSocketsandallowLocalBindingare accepted in config but not reflected in the generated Seatbelt rules for descendant processes.
- #16076 —
excludedCommandsandallowUnixSocketsnot working (closed, not planned — redirected to #10524, #14162, #10767). Same symptom: setting is accepted but has no effect.
- #35686 — Feature request for wildcard/regex support in
sandbox.network.allowUnixSockets. Suggests the socket allowlisting mechanism needs broader improvements.
Sandbox blocking IPC / system services for child processes
- #34876 — Sandbox blocks macOS Security.framework
trustdIPC, breaking all Go binaries (gh,terraform,tofu). Same pattern: Seatbelt profile too restrictive for child process IPC. - #37481 —
excludedCommandsdoes not bypass macOS sandbox for Metal/GPU (IOKit) access. Another case where the sandbox blocks IPC that child processes need. - #38211 — Sandbox silently prevents cmake/ninja builds without error on Linux. Same class of problem on a different platform — build tools that spawn child processes fail silently.
- #36759 — Sandbox sets
TMPDIRto non-existent directory, causing child processes to hang. Related child-process sandbox issue. - #37990 — Sandbox blocks URLSession / CFNetwork on macOS. Another Seatbelt restriction affecting system framework access.
Sandbox config propagation issues
- #37782 —
allowedDomainsdoes not work for Node.js processes (DNS resolution blocked). Settings not propagating to child processes.
How this bug is different
This report differs from existing issues in three ways:
- Root cause identified: We've isolated the problem to
bind()onAF_UNIXsockets being blocked specifically for child/grandchild processes, not for the direct process. Previous reports describe the symptom (hang) without this diagnosis.
- Proof that settings are ignored: We've exhaustively tested every relevant sandbox setting (
allowAllUnixSockets,allowLocalBinding,allowUnixSockets,enableWeakerNestedSandbox,enableWeakerNetworkIsolation,ignoreViolations) and confirmed none resolve the issue — pointing to a gap in how settings are translated to the Seatbelt profile.
- Direct vs child process divergence demonstrated: A direct
dotnet runprocess can createNamedPipeServerStream(which callsbind()on AF_UNIX) inside the sandbox, but a child process spawned by that same process cannot. This narrows the fix to the Seatbelt rules applied to descendant processes.
🤖 Generated with Claude Code
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗