Description
When Worker A calls Worker B (which uses Cloudflare Containers) via a service binding, the Response body returned from container.fetch() inside Worker B's Durable Object is unreadable — it fails with an "internal error" message. The same container and endpoint work fine when called directly (not through a service binding).
Reproduction
- Worker B — a Cloudflare Worker with a Container-backed Durable Object that calls
this.containerFetch(url, opts) and returns the Response.
- Worker A — calls Worker B via a service binding:
env.WORKER_B.fetch(request).
- Worker A receives a
Response whose body cannot be read — attempting to call .text() or .json() on it yields "internal error".
This does not happen when:
- Worker B is called directly (not via service binding)
- Both workers run locally with
wrangler dev
Workaround
We work around this by using a DO RPC method that returns plain structured-clonable data ({ status: number, body: string }) instead of forwarding the Response object. This avoids the broken Response body streaming at the DO → stateless worker boundary.
// Instead of returning container.fetch() Response directly:
async processRequest(path: string, body: string): Promise<{ status: number; body: string }> {
const response = await this.containerFetch(url, { method: 'POST', body, ... });
const text = await response.text();
return { status: response.status, body: text };
}
Environment
- Production (Cloudflare edge)
@cloudflare/containers package
- Observed as of March 2026
Related
Description
When Worker A calls Worker B (which uses Cloudflare Containers) via a service binding, the
Responsebody returned fromcontainer.fetch()inside Worker B's Durable Object is unreadable — it fails with an"internal error"message. The same container and endpoint work fine when called directly (not through a service binding).Reproduction
this.containerFetch(url, opts)and returns theResponse.env.WORKER_B.fetch(request).Responsewhose body cannot be read — attempting to call.text()or.json()on it yields"internal error".This does not happen when:
wrangler devWorkaround
We work around this by using a DO RPC method that returns plain structured-clonable data (
{ status: number, body: string }) instead of forwarding theResponseobject. This avoids the brokenResponsebody streaming at the DO → stateless worker boundary.Environment
@cloudflare/containerspackageRelated
remote: trueworkers-sdk#11114 — similar issue withResponse/ReadableStreamnot serializable over service binding RPC (scoped to local dev withremote: true, but likely the same underlying serialization limitation)