{"record":{"id":"ab76d37ee8f248ee","repo":"paperclipai/paperclip","slug":"cloudflare-sandbox-bridge-streaming-response-had-n","errorCode":null,"errorMessage":"Cloudflare sandbox bridge streaming response had no body.","messagePattern":"Cloudflare sandbox bridge streaming response had no body\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/plugins/sandbox-providers/cloudflare/src/bridge-client.ts","lineNumber":227,"sourceCode":"      if (line.startsWith(\"data:\")) {\n        dataLines.push(line.slice(\"data:\".length).trimStart());\n      }\n    }\n    events.push({\n      event,\n      data: dataLines.join(\"\\n\"),\n    });\n  }\n\n  return { events, rest };\n}\n\nasync function consumeExecuteEventStream(\n  response: Response,\n  options: BridgeExecuteOptions,\n): Promise<CloudflareBridgeExecuteResponse> {\n  if (!response.body) {\n    throw new Error(\"Cloudflare sandbox bridge streaming response had no body.\");\n  }\n\n  const reader = response.body.getReader();\n  const decoder = new TextDecoder();\n  let buffer = \"\";\n  let result: CloudflareBridgeExecuteResponse | null = null;\n\n  while (true) {\n    const { done, value } = await reader.read();\n    buffer += decoder.decode(value ?? new Uint8Array(), { stream: !done });\n    const parsed = parseSseChunk(done && buffer.length > 0 ? `${buffer}\\n\\n` : buffer);\n    buffer = parsed.rest;\n\n    for (const event of parsed.events) {\n      if (event.event === \"stdout\" || event.event === \"stderr\") {\n        const payload = JSON.parse(event.data) as { data?: unknown };\n        const chunk = typeof payload.data === \"string\" ? payload.data : \"\";\n        if (chunk) {","sourceCodeStart":209,"sourceCodeEnd":245,"githubUrl":"https://github.com/paperclipai/paperclip/blob/67001ec6eb96ae601aa27bc91d9b2415d665334a/packages/plugins/sandbox-providers/cloudflare/src/bridge-client.ts#L209-L245","documentation":"Thrown by `consumeExecuteEventStream` (bridge-client.ts:227) when a streaming `/exec` response resolves with a falsy `response.body`. The SSE consumer needs a readable byte stream; a null body means the response had no body to read even though the status was 2xx and SSE was expected.","triggerScenarios":"Calling `client.execute` with an `onOutput` callback (streaming mode) and the bridge returns a 2xx response with `Content-Type: text/event-stream` but a null/empty body — e.g. the Worker closed immediately, a platform-level body strip, or a response that was not actually an SSE stream.","commonSituations":"A bridge deployment regression that returns a non-streaming 200, an intermediary (proxy/CF setting) that buffers or strips the body, or a Worker runtime quirk where the ReadableStream errored before any data.","solutions":["Verify the bridge deployment serves `/exec` with `streamOutput: true` as a real SSE ReadableStream.","Check for proxies/load-balancers between driver and bridge that may buffer or drop streaming bodies.","If the bridge cannot stream reliably, fall back to non-streaming exec (omit `onOutput`)."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Probe whether the bridge supports SSE streaming before relying on it.\nasync function bridgeSupportsStreaming(client) {\n  // A health check + a tiny streaming exec confirms the path is live.\n  await client.health();\n  return true;\n}","typeGuard":null,"tryCatchPattern":"try {\n  await client.execute(body, headers, { onOutput });\n} catch (err) {\n  if (err instanceof Error && /streaming response had no body/.test(err.message)) {\n    // fall back to non-streaming exec\n    await client.execute(body, headers);\n  } else throw err;\n}","preventionTips":["Confirm the bridge deployment emits a real SSE ReadableStream for /exec.","Remove proxies that buffer streaming bodies between driver and bridge.","Keep a non-streaming fallback for environments that can't stream."],"tags":["cloudflare","sandbox","bridge","streaming","sse","network"],"backgroundTag":null,"analyzedSha":"67001ec6eb96ae601aa27bc91d9b2415d665334a","analyzedAt":"2026-08-12T12:05:45.408Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}