{"record":{"id":"82233e7f49038fe5","repo":"can1357/oh-my-pi","slug":"no-response-body-for-v2-compaction-streaming","errorCode":null,"errorMessage":"No response body for V2 compaction streaming","messagePattern":"No response body for V2 compaction streaming","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/agent/src/compaction/compaction-v2-streaming.ts","lineNumber":471,"sourceCode":"\nasync function collectCompactionV2Events(\n\tevents: AsyncIterable<Record<string, unknown>>,\n\trequest: CompactionV2Request,\n): Promise<CompactionV2Response> {\n\tconst state = createCompactionV2CollectionState();\n\tfor await (const event of events) {\n\t\thandleCompactionV2Event(event, undefined, state);\n\t}\n\treturn finishCompactionV2Collection(state, request);\n}\n\nasync function collectCompactionV2Output(\n\tresponse: Response,\n\trequest: CompactionV2Request,\n): Promise<CompactionV2Response> {\n\tconst reader = response.body?.getReader();\n\tif (!reader) {\n\t\tthrow new Error(\"No response body for V2 compaction streaming\");\n\t}\n\n\tconst state = createCompactionV2CollectionState();\n\ttry {\n\t\tconst decoder = new TextDecoder();\n\t\tlet buffer = \"\";\n\t\tlet eventName: string | undefined;\n\t\tlet dataLines: string[] = [];\n\n\t\tconst dispatch = (): void => {\n\t\t\tif (dataLines.length === 0) {\n\t\t\t\teventName = undefined;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\thandleCompactionV2SseEvent(dataLines.join(\"\\n\"), eventName, state);\n\t\t\teventName = undefined;\n\t\t\tdataLines = [];\n\t\t};","sourceCodeStart":453,"sourceCodeEnd":489,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/agent/src/compaction/compaction-v2-streaming.ts#L453-L489","documentation":"collectCompactionV2Output tries to obtain a reader from the HTTP response body to consume the SSE stream; if response.body is null there is nothing to stream and it throws. This happens when the runtime/fetch implementation produced a bodiless response (or the body was already consumed).","triggerScenarios":"The fetch Response returned by the compaction endpoint has a null body — e.g. a custom fetch impl (options.fetch) that returns a cached/stubbed Response without a body, a body already read elsewhere, or a runtime/proxy stripping the streaming body.","commonSituations":"Custom fetch wrappers (logging, caching, retries) that consume or fail to pass through the body; mocking in tests returning new Response(null); undici/worker environments where streaming bodies are unsupported or already locked.","solutions":["Ensure the fetch implementation passes through the raw streaming Response untouched (don't read .text()/.json() first, don't return cached responses)","If you must supply options.fetch, have it return a Response whose body is a readable stream (e.g. new Response(stream))","Check no middleware locks or consumes response.body before collectCompactionV2Output runs","Fall back to a non-streaming compaction path if the environment cannot provide streaming bodies"],"exampleFix":"// before\nfetchImpl: async (url, init) => { const r = await fetch(url, init); await r.text(); return r; } // body consumed\n// after\nfetchImpl: (url, init) => fetch(url, init) // pass Response through untouched","handlingStrategy":"validation","validationCode":"const probe = await fetch(endpoint, init);\nif (!probe.body) {\n  throw new Error(\"Compaction fetch impl must return a Response with a streaming body\");\n}","typeGuard":"function hasStreamingBody(res: Response): boolean {\n  return res.body !== null && !res.bodyUsed;\n}","tryCatchPattern":null,"preventionTips":["Never wrap fetch in ways that consume response.body before returning","In tests, return new Response(stream) rather than Response without a body","Ensure the runtime supports streaming response bodies (avoid stubs in workers/embeddings)"],"tags":["streaming","http","compaction","response-body"],"backgroundTag":"empty-response-body","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}