fix(cloudflare/containers): bind a container's DO namespace and script metadata under one sid - #1271
Merged
Conversation
…t metadata under one sid
Binding rows are collapsed by `sid` (last write wins), so the two `bind`
calls in `bindContainerClass` silently dropped one another whenever the env
key and the Container's logical id matched:
env: { Sandbox: Cloudflare.Container("Sandbox", { className: "Sandbox" }) }
The `containers` row (sid = application logical id) clobbered the
`durable_object_namespace` row (sid = env key), so the Worker uploaded the
Container declaration itself as a `json` binding
(`{"_id":"Effect","op":"alchemy/EffectClass"}`) and `getSandbox(env.Sandbox)`
died at runtime with `t.idFromName is not a function`.
Both rows describe the same env entry, so contribute them in one `bind`.
…worker
Replace the compile-only binding-collection test with real coverage in
Container.test.ts's dev/live matrix: the async fixture (whose Container
logical id equals its env key) is deployed and driven over HTTP.
- /binding asserts env.ECHO is a durable_object_namespace, not the
Container declaration uploaded as json
- /hello asserts the request round-trips Worker -> DO -> container
Without the fix both fail: dev dies with `Durable Object namespace
AsyncEchoObject not found`, live reports
`{"_id":"Effect","op":"alchemy/EffectClass"}`.
AsyncContainer.test.ts is folded in — Container.test.ts now covers the
same stack in both dev and live.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
sam-goodwin
added a commit
that referenced
this pull request
Aug 23, 2026
Issue #1321 reported the #953 symptom — `getContainer(env.X)` dying with `idFromName is not a function` — for a Container bound on an async Worker's `env` in the shape the Containers guide documents: `className` omitted, so the env key, the Container's logical id and the DO class share one name. The fix landed in #1271; this pins that exact shape with a deployed fixture, driven over HTTP in both dev and live. Without #1271 the deployed Worker reports env.Probe as `{"_id":"Effect","op":"alchemy/EffectClass"}`; with it, a namespace that round-trips Worker -> DO class -> container. Co-Authored-By: Claude Opus 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.
A
Cloudflare.Containerbound on an async Worker'senvuploaded as ajsonbinding holding the serialized declaration ({"_id":"Effect","op":"alchemy/EffectClass"}) instead of adurable_object_namespace, whenever the env key and the Container's logical id matched:At runtime
env.Sandboxis then a plain object, and@cloudflare/sandbox'sgetSandbox(ns, id)dies witht.idFromName is not a function.bindContainerClasscontributed the Worker's two halves in separatebindcalls, and binding rows are collapsed bysid— last write wins (Diff.ts), so thecontainersrow silently dropped the namespace row:Both rows describe the same env entry, so they belong under one sid. With them split, the upload carried no DO class at all (
currentDoClassNameByLogicalId: {}), andappendAlchemyAndEnvBindings— which JSON-ifies anyenvvalue not already bound by name — emitted the declaration asjson.The existing async fixture escaped this by naming the Container
AsyncEchoContainerwhile binding it asenv.ECHO; it now usesContainer("ECHO")so the live suite covers the colliding shape. A new offline test (AsyncContainerBinding.test.ts) pins the sid-collapsed rows for both namings.Workaround on released versions: give the Container a logical id that differs from the env key.