{"record":{"id":"a3c21fc0f7dbc7c7","repo":"paperclipai/paperclip","slug":"opencode-sse-event-exceeded-the-retained-payload-l","errorCode":null,"errorMessage":"OpenCode SSE event exceeded the retained payload limit","messagePattern":"OpenCode SSE event exceeded the retained payload limit","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/paperclip-runner/src/drivers/opencode/opencode-server-driver.ts","lineNumber":2409,"sourceCode":"  const address = server.address();\n  if (!address || typeof address === \"string\")\n    throw new Error(\"Unable to reserve OpenCode port\");\n  const port = address.port;\n  await new Promise<void>((resolve, reject) =>\n    server.close((error) => (error ? reject(error) : resolve())),\n  );\n  return port;\n}\n\nasync function* parseSseFrames(\n  stream: ReadableStream<Uint8Array>,\n): AsyncIterable<{ raw: string; data: string }> {\n  const decoder = new TextDecoder();\n  let buffer = \"\";\n  for await (const chunk of stream as unknown as AsyncIterable<Uint8Array>) {\n    buffer += decoder.decode(chunk, { stream: true });\n    if (buffer.length > 1_048_576)\n      throw new Error(\"OpenCode SSE event exceeded the retained payload limit\");\n    let boundary: RegExpExecArray | null;\n    while ((boundary = /\\r?\\n\\r?\\n/.exec(buffer)) !== null) {\n      const rawFrame = buffer.slice(0, boundary.index);\n      const raw = buffer.slice(0, boundary.index + boundary[0].length);\n      const frame = rawFrame.replaceAll(\"\\r\", \"\");\n      buffer = buffer.slice(boundary.index + boundary[0].length);\n      const data = frame\n        .split(\"\\n\")\n        .filter((line) => line.startsWith(\"data:\"))\n        .map((line) => line.slice(5).trimStart())\n        .join(\"\\n\");\n      if (!data || data === \"[DONE]\") continue;\n      yield { raw, data };\n    }\n  }\n}\n\nasync function* parseSse(","sourceCodeStart":2391,"sourceCodeEnd":2427,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/packages/paperclip-runner/src/drivers/opencode/opencode-server-driver.ts#L2391-L2427","documentation":"Thrown while parsing the OpenCode SSE stream when the accumulated buffer of a single un-terminated SSE event exceeds 1,048,576 bytes (1 MiB). The driver caps retained payload size to prevent unbounded memory growth from a misbehaving or malicious server.","triggerScenarios":"A streamed chunk sequence where no \\r?\\n\\r?\\n frame boundary appears and buffered data surpasses 1 MiB — e.g. the server sends one giant event, garbage data without blank-line separators, or a binary (non-SSE) response body.","commonSituations":"Proxy returning a non-SSE HTML page (no frame boundaries); server emitting a single very large tool-output event; corrupted stream due to compression not being decompressed.","solutions":["Inspect what the server actually sent at that point — if it is HTML/JSON error content, the endpoint path or auth is wrong, not the payload size.","Check whether a proxy/gateway is buffering or mangling the SSE stream so frame boundaries are lost.","Reduce the size of provider events (e.g. huge tool outputs) so individual events stay under 1 MiB.","If legitimate events can exceed 1 MiB, raise the limit in the SSE parser and document the memory trade-off."],"exampleFix":"// before\nif (buffer.length > 1_048_576)\n  throw new Error(\"OpenCode SSE event exceeded the retained payload limit\");\n\n// after\nconst SSE_MAX_BUFFER = 4 * 1_048_576; // allow large tool outputs\nif (buffer.length > SSE_MAX_BUFFER)\n  throw new Error(`OpenCode SSE event exceeded ${SSE_MAX_BUFFER} bytes`);","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  for await (const frame of sseFrames(stream)) consume(frame);\n} catch (e) {\n  if (e instanceof Error && e.message.includes(\"retained payload limit\")) {\n    // dump first bytes of raw stream to see what the server actually sent (HTML? giant event?)\n  }\n}","preventionTips":["Verify the event endpoint returns text/event-stream, not HTML/JSON error content","Keep individual provider events (tool outputs) under 1 MiB","Ensure proxies do not strip SSE frame boundaries or mis-handle compression"],"tags":["sse","streaming","payload-size","limit"],"backgroundTag":"payload-too-large","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}