{"record":{"id":"bb9e2932f9354578","repo":"can1357/oh-my-pi","slug":"perplexity-ask-api-returned-no-response-body","errorCode":null,"errorMessage":"Perplexity ask API returned no response body","messagePattern":"Perplexity ask API returned no response body","errorType":"exception","errorClass":"SearchProviderError","httpStatus":500,"severity":"error","filePath":"packages/coding-agent/src/web/search/providers/perplexity.ts","lineNumber":737,"sourceCode":"\t\tresponse = await (params.fetch ?? fetch)(PERPLEXITY_OAUTH_ASK_URL, requestInit);\n\t} catch (error) {\n\t\tif (params.signal?.aborted) throw error;\n\t\tresponse = await (params.fetch ?? fetch)(PERPLEXITY_OAUTH_ASK_URL, requestInit);\n\t}\n\n\tif (!response.ok) {\n\t\tconst errorText = await response.text();\n\t\tconst classified = classifyProviderHttpError(\"perplexity\", response.status, errorText);\n\t\tif (classified) throw classified;\n\t\tthrow new SearchProviderError(\n\t\t\t\"perplexity\",\n\t\t\t`Perplexity ask API error (${response.status}): ${errorText}`,\n\t\t\tresponse.status,\n\t\t);\n\t}\n\n\tif (!response.body) {\n\t\tthrow new SearchProviderError(\"perplexity\", \"Perplexity ask API returned no response body\", 500);\n\t}\n\n\tlet answer = \"\";\n\tlet model: string | undefined;\n\tlet finalRequestId: string | undefined;\n\tconst sourcesByUrl = new Map<string, SearchSource>();\n\tlet mergedEvent: PerplexityOAuthStreamEvent = { blocks: [] };\n\n\tfor await (const event of readSseJson<PerplexityOAuthStreamEvent>(response.body, params.signal)) {\n\t\tif (event.error_code) {\n\t\t\tconst message = event.error_message ?? event.error_code;\n\t\t\tthrow new SearchProviderError(\"perplexity\", `Perplexity ask stream error: ${message}`, 400);\n\t\t}\n\n\t\tmergedEvent = mergeOAuthEventSnapshot(mergedEvent, event);\n\n\t\tconst eventAnswer = buildOAuthAnswer(mergedEvent);\n\t\tif (eventAnswer.length > 0) {","sourceCodeStart":719,"sourceCodeEnd":755,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/web/search/providers/perplexity.ts#L719-L755","documentation":"After a successful (2xx) HTTP response from the Perplexity ask API, the response carried no readable body stream, so the SSE event stream cannot be consumed. The provider throws a SearchProviderError with status 500 to signal an unexpected empty response from the server.","triggerScenarios":"fetch to the Perplexity ask endpoint resolves ok but response.body is null — happens with some proxies/mocks, certain HTTP/1.1 empty-body responses, or runtimes where streaming bodies are unavailable.","commonSituations":"Corporate proxy stripping/short-circuiting responses, custom fetch implementations (e.g. testing mocks) that return bodies-less Response objects, middleboxes returning empty 200s.","solutions":["Retry the request — this is often transient infrastructure behavior","Check any custom fetch/proxy passed via params.fetch for behavior that drops bodies","Bypass interfering proxies or TLS-intercepting middlewares","Fall back to an alternate provider if it reproduces consistently"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  return await perplexityAsk(params);\n} catch (err) {\n  if (err instanceof SearchProviderError && err.message.includes(\"no response body\")) {\n    return await withRetry(() => perplexityAsk(params), { attempts: 2 });\n  }\n  throw err;\n}","preventionTips":["Avoid custom fetch wrappers that can return bodyless Responses","Test through the same proxies/middleboxes used in production","Retry transiently at the call site"],"tags":["network","streaming","perplexity","empty-response"],"backgroundTag":"empty-response-body","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}