{"record":{"id":"d03305ec0dafa1ee","repo":"can1357/oh-my-pi","slug":"perplexity-api-error-status-details","errorCode":null,"errorMessage":"Perplexity API error (${status}): ${details}","messagePattern":"Perplexity API error \\((.+?)\\): (.+?)","errorType":"exception","errorClass":"SearchProviderError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/web/search/providers/perplexity.ts","lineNumber":498,"sourceCode":"\nasync function drainAssistantStream(stream: AssistantMessageEventStream): Promise<AssistantMessage> {\n\tlet finalMessage: AssistantMessage | undefined;\n\tfor await (const event of stream) {\n\t\tif (event.type === \"done\") {\n\t\t\tfinalMessage = event.message;\n\t\t} else if (event.type === \"error\") {\n\t\t\tfinalMessage = event.error;\n\t\t}\n\t}\n\treturn finalMessage ?? stream.result();\n}\n\nfunction throwPerplexityStreamError(message: AssistantMessage): never {\n\tconst status = message.errorStatus ?? 500;\n\tconst details = message.errorMessage ?? \"Perplexity API stream failed\";\n\tconst classified = classifyProviderHttpError(\"perplexity\", status, details);\n\tif (classified) throw classified;\n\tthrow new SearchProviderError(\"perplexity\", `Perplexity API error (${status}): ${details}`, status);\n}\n\n/** Call Perplexity API-key endpoint (or OpenRouter) through the shared OpenAI streaming providers. */\nasync function callPerplexityApi(\n\tconfig: ApiConfig,\n\trequest: PerplexityRequest,\n\tfetchImpl: FetchImpl | undefined,\n\tsignal?: AbortSignal,\n\ttimeoutMs?: number,\n): Promise<SearchResponse> {\n\tconst metadata: PerplexityApiStreamMetadata = {};\n\tconst context = buildPerplexityContext(request);\n\tconst requestSignal = withHardTimeout(signal, timeoutMs);\n\tconst onSseEvent = (event: { data: string }): void => {\n\t\tcollectPerplexityMetadata(metadata, event.data);\n\t};\n\n\tconst message = config.useResponses","sourceCodeStart":480,"sourceCodeEnd":516,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/web/search/providers/perplexity.ts#L480-L516","documentation":"throwPerplexityStreamError converts a failed assistant stream message from the Perplexity API-key (or OpenRouter) path into a thrown error. It first tries classifyProviderHttpError for a typed classification; if unclassified it throws a SearchProviderError for provider \"perplexity\" with a message embedding the HTTP-like status and error details reported on the stream message.","triggerScenarios":"callPerplexityApi's OpenAI-compatible streaming call ends with an error AssistantMessage (message.errorStatus set) — HTTP auth failure, quota exhaustion, invalid model/parameter, or mid-stream server error.","commonSituations":"Invalid or revoked Perplexity API key, exceeding monthly credits, requesting an unavailable model, OpenRouter key with insufficient balance.","solutions":["Read the status and details embedded in the message to identify the upstream cause","Verify the Perplexity API key and remaining credits","If 429/402, wait or top up credits before retrying","Retry with a supported model name if the model was rejected"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if (!process.env.PERPLEXITY_API_KEY) throw new Error('Perplexity API key missing');","typeGuard":"function isSearchProviderError(e: unknown): e is SearchProviderError {\n  return e instanceof SearchProviderError;\n}","tryCatchPattern":"try {\n  return await perplexitySearch(params);\n} catch (err) {\n  if (err instanceof SearchProviderError && /Perplexity API error \\((\\d+)\\)/.test(err.message)) {\n    const status = Number(err.message.match(/\\((\\d+)\\)/)?.[1]);\n    if (status === 429 || status === 402) await retryLater();\n  }\n  throw err;\n}","preventionTips":["Monitor Perplexity credit balance before bulk searches","Pin supported model names","Surface stream failures to users with the embedded status code"],"tags":["network","http","web-search","streaming","perplexity"],"backgroundTag":"search-provider-http-error","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}