{"record":{"id":"67e3d3ae8fbd5e21","repo":"paperclipai/paperclip","slug":"cloudflare-sandbox-bridge-streaming-response-ended","errorCode":null,"errorMessage":"Cloudflare sandbox bridge streaming response ended without a completion event.","messagePattern":"Cloudflare sandbox bridge streaming response ended without a completion event\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/plugins/sandbox-providers/cloudflare/src/bridge-client.ts","lineNumber":269,"sourceCode":"      if (event.event === \"complete\") {\n        result = JSON.parse(event.data) as CloudflareBridgeExecuteResponse;\n        continue;\n      }\n\n      if (event.event === \"error\") {\n        const payload = JSON.parse(event.data) as { error?: unknown };\n        const message = typeof payload.error === \"string\" && payload.error.trim().length > 0\n          ? payload.error\n          : \"Cloudflare sandbox bridge streaming command failed.\";\n        throw new Error(message);\n      }\n    }\n\n    if (done) break;\n  }\n\n  if (result) return result;\n  throw new Error(\"Cloudflare sandbox bridge streaming response ended without a completion event.\");\n}\n\nexport function createCloudflareBridgeClient(options: BridgeClientOptions) {\n  const { config } = options;\n  const apiPrefix = \"/api/paperclip-sandbox/v1\";\n\n  return {\n    health(extraHeaders?: BridgeClientHeaders): Promise<CloudflareBridgeHealthResponse> {\n      return requestJson<CloudflareBridgeHealthResponse>(config, `${apiPrefix}/health`, { method: \"GET\" }, extraHeaders);\n    },\n\n    probe(body: CloudflareBridgeProbeRequest, extraHeaders?: BridgeClientHeaders): Promise<CloudflareBridgeProbeResponse> {\n      return requestJson<CloudflareBridgeProbeResponse>(\n        config,\n        `${apiPrefix}/probe`,\n        { method: \"POST\", body: JSON.stringify(body) },\n        extraHeaders,\n      );","sourceCodeStart":251,"sourceCodeEnd":287,"githubUrl":"https://github.com/paperclipai/paperclip/blob/67001ec6eb96ae601aa27bc91d9b2415d665334a/packages/plugins/sandbox-providers/cloudflare/src/bridge-client.ts#L251-L287","documentation":"Thrown by `consumeExecuteEventStream` (bridge-client.ts:269) when the SSE stream ends (reader `done`) without the bridge ever emitting a `complete` event carrying the `CloudflareBridgeExecuteResponse`. Every streaming exec is contractually terminated by a `complete` event with exit code/stdout/stderr; its absence means the stream closed prematurely.","triggerScenarios":"A streaming `/exec` call where the SSE connection terminates (Worker evicted, connection drop, heartbeat gap exceeding edge idle timeout, or the stream closed after only stdout/stderr events) before the `complete` event is sent.","commonSituations":"Cloudflare Worker CPU/wall-clock limit hit mid-command, the sandbox was evicted during execution, an edge idle timeout closed the SSE stream during a silent command, or the bridge crashed before emitting complete.","solutions":["Retry the exec; transient stream termination is often recoverable.","Re-acquire/resume the lease if the sandbox may have been evicted (verifySentinel / 409 handling).","For long-silent commands, ensure the bridge heartbeat (15s keepalives) is reaching the client, and consider non-streaming exec for short commands."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":"function isStreamPrematureClose(e: unknown): boolean {\n  return e instanceof Error && /ended without a completion event/.test(e.message);\n}","tryCatchPattern":"try {\n  await client.execute(body, headers, { onOutput });\n} catch (err) {\n  if (isStreamPrematureClose(err)) {\n    await client.resumeLease({ providerLeaseId }, headers); // recover if evicted\n    await client.execute(body, headers, { onOutput });      // one retry\n  } else throw err;\n}","preventionTips":["Resume the lease after a premature close (the sandbox may have been evicted).","Use keepAlive + heartbeats to keep silent SSE commands alive at the edge.","Prefer non-streaming for short commands to avoid edge idle timeouts."],"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"}