You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
sandbox-runner v1.10.4: "Cannot find module '/sandbox_api/.build/anonymous-pipes.node'" inside the microVM guest (502 on every execution) #329
With the official ghcr.io/librechat-ai/code-interpreter-sandbox-runner image (v1.10.4, sha256:13a76d9d…eb62), every code execution fails in the microVM guest. The client
(LibreChat v0.8.8) gets a 502 from the Code API.
Deployment: self-hosted, microVM runner (libkrun) + NsJail, HARDENED_SANDBOX_MODE, JWT auth.
JWT is accepted, worker and runner pick up the job, the microVM boots, then:
Failed to spawn nsjail: Cannot find module '/sandbox_api/.build/anonymous-pipes.node'
api/Dockerfile (target sandbox-runner-true) copies the addon to /usr/local/lib/anonymous-pipes.node and sets ENV SANDBOX_PIPE_ADDON, but that is
image config, it does not reach the guest.
Inside /sandbox-rootfs.img, the addon exists at /usr/local/lib/anonymous-pipes.node,
while /sandbox_api/.build/ only contains index.js and tool-call-pipe-broker.cjs.
The launcher (launcher/src/main.rs, is_allowed_guest_env_key) only forwards an
allowlist of env vars to the guest, and SANDBOX_PIPE_ADDON is not in it. entrypoint.sh
and guest-dns.sh don't export it either.
So in the guest, the env var is unset and the fallback path does not exist.
Same code on main (checked at c854ab5).
Local workaround (works)
Copy the official addon into the expected path inside the guest rootfs, no rebuild: debugfs -w on a copy of /sandbox-rootfs.img, write /usr/local/lib/anonymous-pipes.node
to /sandbox_api/.build/anonymous-pipes.node (0755, root:root), e2fsck -fn clean, then docker cp the patched image back and docker commit a derived runner image.
Executions now succeed (Python, files out, network isolation all as expected).
Possible fixes (any one of these)
Place the addon at /sandbox_api/.build/anonymous-pipes.node when building the guest rootfs.
Add SANDBOX_PIPE_ADDON to the launcher's guest env allowlist.
Fall back to /usr/local/lib/anonymous-pipes.node in pipe-process.ts.
Happy to test a fixed image. Thanks for the project!
Worth stressing: sandbox-runner reports healthy throughout. The healthcheck never spawns nsjail, so container state, /v1/health and the whole compose stack all look correct. Only an actual execution reveals it.
2. Root cause
api/src/pipe-process.ts:9 resolves the native addon:
SANDBOX_PIPE_ADDON is not set in the shipped runner images, so it falls back to .build/anonymous-pipes.node — which does not exist. The addon is built to /usr/local/lib/anonymous-pipes.node instead.
In api/Dockerfile, ENV SANDBOX_PIPE_ADDON is set in exactly two stages:
48:FROM nsjail-builder AS nsjail-ipc-test
49:ENV SANDBOX_PIPE_ADDON=/usr/local/lib/anonymous-pipes.node ← test stage
90:FROM oven/bun:1.4.2-debian AS sandbox-build
135:ENV SANDBOX_PIPE_ADDON=/usr/local/lib/anonymous-pipes.node ← not inherited below
Neither reaches the runner targets:
252:FROM fedora:43 AS sandbox-runner-base ← no ENV
277:FROM debian:bookworm AS sandbox-rootfs-image
COPY --from=sandbox-build / /sandbox-rootfs/ ← copies FILES; ENV does not travel
294:FROM sandbox-runner-base AS sandbox-runner-baked
304:FROM sandbox-runner-base AS sandbox-runner
315:FROM sandbox-runner-baked AS sandbox-runner-true ← KVM_ENABLED=true
316:FROM sandbox-runner AS sandbox-runner-false ← KVM_ENABLED=false
COPY --from=sandbox-build / /sandbox-rootfs/ carries the addon file into the guest, but ENV is image metadata and does not survive a COPY. Both runner targets descend from sandbox-runner-base (fedora:43), which never sets the variable, and no entrypoint sets it either.
So the file is present and the pointer to it is missing.
Confirmed by loop-mounting the baked guest image (sandbox-rootfs.img) from a running sandbox-runner:
# addon is in the guest:
/mnt/rfs/usr/local/lib/anonymous-pipes.node
# but the fallback directory has no .node file:
/mnt/rfs/sandbox_api/.build/ -> index.js tool-call-pipe-broker.cjs
And in the running container:
$ docker exec sandbox-runner printenv | grep SANDBOX_PIPE_ADDON
(nothing)
$ docker exec sandbox-runner ls /usr/local/lib/anonymous-pipes.node
No such file or directory
3. Why operators cannot work around it
Setting SANDBOX_PIPE_ADDON via .env or a compose override does not work for the KVM path. launcher/src/main.rs filters the guest environment through an explicit allowlist:
SANDBOX_PIPE_ADDON appears zero times in launcher/src/main.rs and is not in ALLOW_EXACT, so it is dropped before reaching the guest. There is no configuration-level fix.
4. Why CI did not catch it
The IPC test stage sets the variable that the shipped stages do not:
FROM nsjail-builder AS nsjail-ipc-test
ENV SANDBOX_PIPE_ADDON=/usr/local/lib/anonymous-pipes.node
So the pipe machinery is exercised in an environment configured differently from the one released. The test passes; the artifact fails.
5. Scope
Introduced by a62d69e — "🔒 Harden Runner Supervisors with Anonymous Pipes" (#315). git tag --contains a62d69e returns v1.10.4 and nothing else, and v1.10.4 is exactly v1.10.3 plus that one commit. v1.10.3 and earlier are unaffected.
Both Compose targets are built from the affected chain, since docker-compose.yaml selects target: sandbox-runner-${KVM_ENABLED:-true}.
The published images are built from those same targets (.github/workflows/images.yml):
so the v1.10.4 release artifacts appear to carry the defect as well, not only source builds.
Verified empirically on sandbox-runner-true (KVM) only. We have not run sandbox-runner-false; that it is equally affected is inferred from the Dockerfile stage graph, since it shares sandbox-runner-base and the same ENV gap. Worth confirming on your side before deciding the fix.
6. Suggested fixes
Any one of these closes it:
Set the variable in the runner stages. Add to sandbox-runner-base, or to both sandbox-runner-baked and sandbox-runner:
Arguably the more robust option — it removes the dependency on an env var crossing an image and a VM boundary.
Add SANDBOX_PIPE_ADDON to ALLOW_EXACT in launcher/src/main.rs. Needed only if you want operators to be able to override the path; not sufficient alone, since nothing sets it by default.
Worth considering alongside
Fail loudly at startup rather than per-execution. The runner answers its healthcheck happily while being structurally incapable of running anything. A startup probe that resolves the addon once — the same require the execution path performs — would turn a silent 500-per-request into an obvious boot failure.
Run the IPC test against a shipped stage.nsjail-ipc-test setting SANDBOX_PIPE_ADDON itself is what allowed this through; a smoke test that executes one trivial job against sandbox-runner-true would have caught it immediately.
7. Environment
code-interpreter v1.10.4, built from source via docker-compose.yaml, KVM_ENABLED=true (target sandbox-runner-true)
Activity
Spyros-Vl commentedon Oct 12, 2026
I had the same exact issue and prepared the following bug report, I will post it here istead of making duplicate bug.
v1.10.4: every sandbox execution fails —
SANDBOX_PIPE_ADDONis never set in the shipped runner imagesSeverity: v1.10.4 cannot execute code at all. The container reports healthy, so this is only visible on a real execution.
Affected:
v1.10.4only. It is the release that introduced the addon.1. Symptom
Every execution fails.
POST /api/v2/executeonsandbox-runnerreturns 500, surfacing upstream assandbox_execution_failed:{"level":50,"job":"sbx_k57Vo0mywOHC7RkV2DGHoA","err":{ "type":"Error", "message":"Failed to spawn nsjail: Cannot find module '/sandbox_api/.build/anonymous-pipes.node'\nRequire stack:\n- /sandbox_api/.build/index.js" },"msg":"Error executing job"}Worth stressing:
sandbox-runnerreportshealthythroughout. The healthcheck never spawns nsjail, so container state,/v1/healthand the whole compose stack all look correct. Only an actual execution reveals it.2. Root cause
api/src/pipe-process.ts:9resolves the native addon:SANDBOX_PIPE_ADDONis not set in the shipped runner images, so it falls back to.build/anonymous-pipes.node— which does not exist. The addon is built to/usr/local/lib/anonymous-pipes.nodeinstead.In
api/Dockerfile,ENV SANDBOX_PIPE_ADDONis set in exactly two stages:Neither reaches the runner targets:
COPY --from=sandbox-build / /sandbox-rootfs/carries the addon file into the guest, butENVis image metadata and does not survive aCOPY. Both runner targets descend fromsandbox-runner-base(fedora:43), which never sets the variable, and no entrypoint sets it either.So the file is present and the pointer to it is missing.
Confirmed by loop-mounting the baked guest image (
sandbox-rootfs.img) from a runningsandbox-runner:And in the running container:
3. Why operators cannot work around it
Setting
SANDBOX_PIPE_ADDONvia.envor a compose override does not work for the KVM path.launcher/src/main.rsfilters the guest environment through an explicit allowlist:SANDBOX_PIPE_ADDONappears zero times inlauncher/src/main.rsand is not inALLOW_EXACT, so it is dropped before reaching the guest. There is no configuration-level fix.4. Why CI did not catch it
The IPC test stage sets the variable that the shipped stages do not:
So the pipe machinery is exercised in an environment configured differently from the one released. The test passes; the artifact fails.
5. Scope
Introduced by
a62d69e— "🔒 Harden Runner Supervisors with Anonymous Pipes" (#315).git tag --contains a62d69ereturnsv1.10.4and nothing else, andv1.10.4is exactlyv1.10.3plus that one commit. v1.10.3 and earlier are unaffected.Both Compose targets are built from the affected chain, since
docker-compose.yamlselectstarget: sandbox-runner-${KVM_ENABLED:-true}.The published images are built from those same targets (
.github/workflows/images.yml):so the v1.10.4 release artifacts appear to carry the defect as well, not only source builds.
Verified empirically on
sandbox-runner-true(KVM) only. We have not runsandbox-runner-false; that it is equally affected is inferred from the Dockerfile stage graph, since it sharessandbox-runner-baseand the sameENVgap. Worth confirming on your side before deciding the fix.6. Suggested fixes
Any one of these closes it:
Set the variable in the runner stages. Add to
sandbox-runner-base, or to bothsandbox-runner-bakedandsandbox-runner:ENV SANDBOX_PIPE_ADDON=/usr/local/lib/anonymous-pipes.nodeThe file is already in place via the existing
COPY.Or place the addon where the fallback already looks, so the code path works with no environment at all:
COPY --from=nsjail-builder /usr/local/lib/anonymous-pipes.node /sandbox_api/.build/anonymous-pipes.nodeArguably the more robust option — it removes the dependency on an env var crossing an image and a VM boundary.
Add
SANDBOX_PIPE_ADDONtoALLOW_EXACTinlauncher/src/main.rs. Needed only if you want operators to be able to override the path; not sufficient alone, since nothing sets it by default.Worth considering alongside
Fail loudly at startup rather than per-execution. The runner answers its healthcheck happily while being structurally incapable of running anything. A startup probe that resolves the addon once — the same
requirethe execution path performs — would turn a silent 500-per-request into an obvious boot failure.Run the IPC test against a shipped stage.
nsjail-ipc-testsettingSANDBOX_PIPE_ADDONitself is what allowed this through; a smoke test that executes one trivial job againstsandbox-runner-truewould have caught it immediately.7. Environment
v1.10.4, built from source viadocker-compose.yaml,KVM_ENABLED=true(targetsandbox-runner-true)/dev/kvmpresent, libkrun microVM + NsJailv1.10.3on the same host, same configuration, works correctly — the only delta isa62d69etwltwk commentedon Oct 12, 2026
Oh sorry !