Repository navigation
fix(void): restore Container Durable Object bindings in the dev server - #696
Merged
Merged
Conversation
Since 1.5.0, an app that uses `void/sandbox` can't reach its Sandbox in
the dev server. `getSandbox()` throws:
env: Missing Cloudflare binding 'SANDBOX'.
Other Container classes lose their binding too. 1.4.0 works.
Since 8b26dba, the config for `@cloudflare/vite-plugin` 2.0 comes from
`migrateBuiltWranglerConfig()`, which rewrites the binding of each
Container class as `unsafe:durable_object_namespace`. That form is only
for the Worker upload. Miniflare skips unsafe bindings that have no dev
plugin, so the class and its Container still exist in dev, but `env` has
no binding for them.
## Fix
In serve, `void:cloudflare-config` turns these bindings back into regular
`durable-object` bindings. Builds and deploys keep the unsafe form.
Only the generated binding of a Container class changes. Unsafe bindings
in the user's config use the same type and may name another Worker, even
one with a class of the same name. A local binding would reach the wrong
class, or stop workerd from starting if this Worker doesn't define it.
## Not fixed here
These also regressed in 1.5.0:
- `vite preview` with a Sandbox fails with the same error.
- A Container with a Dockerfile `image` outside `void/sandbox` stops the
dev server from starting.
- A Container in an auxiliary Worker stops the dev server from starting.
## Tests
`plugin-cloudflare-v2.test.ts` runs the real plugin and Miniflare with a
Docker stub, so it needs no Docker. In the dev server, Container classes
and a regular Durable Object are bound, and unsafe bindings from the
user's config are not, including one that names another Worker's class
with the same name as a local Container. In the build, Container classes
keep the unsafe form. The test fails without the fix and without either
check.
## Verification
- `vp test run`: 772 files pass, 1 skipped (15,810 tests pass, 29
skipped).
- `vp run check`: 33/33 pass.
- By hand under `vp dev` with Docker: `getSandbox('x')` runs `echo hi`,
the explorer lists `SANDBOX`, and the `kitchen-sink-sandbox` acceptance
route passes all 12 checks. A renamed binding and class, a
`defineDurableObject` class with a Container and `CLOUDFLARE_ENV` also
work.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J8F8mZpYEz7gFr91ZVxeVB
cpojer
self-requested a review
November 4, 2026 04:10
cpojer
approved these changes
Nov 4, 2026
cpojer
left a comment
Member
There was a problem hiding this comment.
Ahh, sorry for the breakage and thanks for the fix. We'll publish 1.6.0 with this later today (eta ~4 hours).
Brooooooklyn
added a commit
that referenced
this pull request
Nov 4, 2026
…697) Fixes a flaky unit run seen on #669: every test passed, but Vitest failed the job on an uncaught `Error: write EPIPE` from `dockerBuild` in `@cloudflare/vite-plugin` (test: "binds Container Durable Objects in the dev server…", added in #696). ``` dockerBuild: spawn(docker build … -f -) → child.stdin.write(Dockerfile) old stub #!/bin/sh exit 0 → on a busy runner the stub exits before the write → write EPIPE, no error listener → uncaught → job fails new stub if [ "$1" = build ]; then cat >/dev/null; fi exit 0 → the stub waits until stdin closes, so the write always lands ``` Reproduced locally by blocking the parent between `spawn` and `write` (same order as the CI trace): | stub | result | | --- | --- | | old | `Error: write EPIPE` | | new | ok | Only `build` reads stdin, so other Docker calls cannot block on it. Test-only change. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Since 1.5.0, an app that uses
void/sandboxcan't reach its Sandbox in the dev server.getSandbox()throws:Other Container classes lose their binding too. 1.4.0 works.
Since 8b26dba, the config for
@cloudflare/vite-plugin2.0 comes frommigrateBuiltWranglerConfig(), which rewrites the binding of each Container class asunsafe:durable_object_namespace. That form is only for the Worker upload. Miniflare skips unsafe bindings that have no dev plugin, so the class and its Container still exist in dev, butenvhas no binding for them.Fix
In serve,
void:cloudflare-configturns these bindings back into regulardurable-objectbindings. Builds and deploys keep the unsafe form.Only the generated binding of a Container class changes. An unsafe binding in the user's config has the same type, but it may point at another Worker, even at a class with the same name as a local Container. Turning it into a local binding would connect it to the local class instead, or stop workerd from starting if this Worker has no such class.
docs/guide/sandboxes.mdalready describes local development with Docker, so the docs do not change.Not fixed here
These also regressed in 1.5.0:
vite previewwith a Sandbox fails with the same error.imageoutsidevoid/sandboxstops the dev server from starting.Tests
packages/void/test/unit/plugin-cloudflare-v2.test.tsruns the real plugin and Miniflare with a Docker stub, so it needs no Docker. In the dev server, Container classes and a regular Durable Object are bound, and unsafe bindings from the user's config are not, including one that names another Worker's class with the same name as a local Container. In the build, Container classes keep the unsafe form.The test fails without the fix, without the Container class check and without the generated-form check.
Verification
vp test run: 772 files pass, 1 skipped (15,810 tests pass, 29 skipped).vp run check: 33/33 pass.vp devwith Docker:getSandbox('x')runsecho hi, and the local explorer listsSANDBOX.kitchen-sink-sandboxfixture passes all 12 checks.defineDurableObjectclass with a Container, andCLOUDFLARE_ENVpointing at an environment with only anamealso work.