Skip to content

fix(sandbox): keep vz sockets inside the AF_UNIX path limit - #222

Merged
quickbeard merged 1 commit into
mainfrom
fix/sandbox-socket-path
Aug 13, 2026
Merged

quickbeard merged 1 commit into
mainfrom
fix/sandbox-socket-path

Conversation

@quickbeard

Copy link
Copy Markdown
Owner

Reported from a real sandbox: creating one named codev-work failed with

sandbox VM failed: bind() failed for …/sandboxes/codev-work/runtime/server.sock:
No such file or directory

Root cause

sun_path is capped at 104 bytes on macOS (103 usable), and the cap is enforced by silent truncation rather than an error. That path is exactly 104 characters, so the helper bound a truncated path and everything downstream looked for a socket that was not there — surfacing as a confusing ENOENT. Reproduced directly: binding that path from Node reports success, then unlink of the same path fails with ENOENT because the socket actually landed elsewhere.

The app data directory alone is ~74 characters, so only ~29 remain for the sandbox name plus /runtime/server.sock. Sandbox names of 10 characters already overflow — which is why the names used during testing (e2e, work, sectest) all fit and hid the bug.

Fix

Sockets move to a short per-user directory keyed by a hash of the sandbox's data dir: <tmp>/codev-sbx-<hash10>/{server,broker}.sock, created 0700 (the system temp dir is shared on Linux, so the sockets inside must not be reachable by other users). Unique per sandbox, stable across starts, and ~83 characters on macOS — far clear of the limit. vm.json and the rest of the runtime state stay in the data dir.

Verification

  • Live e2e-vz on the published image: health: OK / path api: OK / broker: OK / e2e OK
  • New unit test pins socket path length under the limit for names far longer than the one that broke, and asserts each sandbox gets its own directory
  • Package suite: 96 pass / 2 skip

Note on the other backends

WSL uses TCP, so it is unaffected. bubblewrap's socket lives under a much shorter base (~/.config/...) against a higher limit (108 on Linux), so it has real headroom — left alone rather than changed blind, but worth revisiting when the Linux path gets its first real run.

🤖 Generated with Claude Code

A sandbox whose name pushed its socket path past 103 characters failed
to start with "bind() failed ... No such file or directory". The cap is
enforced by silent truncation, so the helper bound a path nobody was
listening on. The app data directory alone is ~74 characters, so
"codev-work" was already enough to overflow.

Sockets now live in a short per-user directory keyed by a hash of the
sandbox's data dir (0700, since the system temp dir is shared on Linux),
which keeps them unique per sandbox and well clear of the limit. vm.json
and the rest of the runtime state stay where they were.

Verified: live vz e2e green (health / path api / broker), and a unit
test pins socket paths under the limit for names far longer than the one
that broke.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@quickbeard
quickbeard merged commit 2a63dd1 into main Aug 13, 2026
0 of 5 checks passed
@quickbeard
quickbeard deleted the fix/sandbox-socket-path branch August 13, 2026 09:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant