can1357/oh-my-pi · error

No response body for V2 compaction streaming

Error message

No response body for V2 compaction streaming

What it means

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).

Source

Thrown at packages/agent/src/compaction/compaction-v2-streaming.ts:471

async function collectCompactionV2Events(
	events: AsyncIterable<Record<string, unknown>>,
	request: CompactionV2Request,
): Promise<CompactionV2Response> {
	const state = createCompactionV2CollectionState();
	for await (const event of events) {
		handleCompactionV2Event(event, undefined, state);
	}
	return finishCompactionV2Collection(state, request);
}

async function collectCompactionV2Output(
	response: Response,
	request: CompactionV2Request,
): Promise<CompactionV2Response> {
	const reader = response.body?.getReader();
	if (!reader) {
		throw new Error("No response body for V2 compaction streaming");
	}

	const state = createCompactionV2CollectionState();
	try {
		const decoder = new TextDecoder();
		let buffer = "";
		let eventName: string | undefined;
		let dataLines: string[] = [];

		const dispatch = (): void => {
			if (dataLines.length === 0) {
				eventName = undefined;
				return;
			}
			handleCompactionV2SseEvent(dataLines.join("\n"), eventName, state);
			eventName = undefined;
			dataLines = [];
		};

View on GitHub (pinned to 9690622007)

Solutions

  1. Ensure the fetch implementation passes through the raw streaming Response untouched (don't read .text()/.json() first, don't return cached responses)
  2. If you must supply options.fetch, have it return a Response whose body is a readable stream (e.g. new Response(stream))
  3. Check no middleware locks or consumes response.body before collectCompactionV2Output runs
  4. Fall back to a non-streaming compaction path if the environment cannot provide streaming bodies

Example fix

// before
fetchImpl: async (url, init) => { const r = await fetch(url, init); await r.text(); return r; } // body consumed
// after
fetchImpl: (url, init) => fetch(url, init) // pass Response through untouched
Defensive patterns

Strategy: validation

Validate before calling

const probe = await fetch(endpoint, init);
if (!probe.body) {
  throw new Error("Compaction fetch impl must return a Response with a streaming body");
}

Type guard

function hasStreamingBody(res: Response): boolean {
  return res.body !== null && !res.bodyUsed;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/82233e7f49038fe5. Report an issue: GitHub.