can1357/oh-my-pi · error · SearchProviderError

Perplexity API error (${status}): ${details}

Error message

Perplexity API error (${status}): ${details}

What it means

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.

Source

Thrown at packages/coding-agent/src/web/search/providers/perplexity.ts:498

async function drainAssistantStream(stream: AssistantMessageEventStream): Promise<AssistantMessage> {
	let finalMessage: AssistantMessage | undefined;
	for await (const event of stream) {
		if (event.type === "done") {
			finalMessage = event.message;
		} else if (event.type === "error") {
			finalMessage = event.error;
		}
	}
	return finalMessage ?? stream.result();
}

function throwPerplexityStreamError(message: AssistantMessage): never {
	const status = message.errorStatus ?? 500;
	const details = message.errorMessage ?? "Perplexity API stream failed";
	const classified = classifyProviderHttpError("perplexity", status, details);
	if (classified) throw classified;
	throw new SearchProviderError("perplexity", `Perplexity API error (${status}): ${details}`, status);
}

/** Call Perplexity API-key endpoint (or OpenRouter) through the shared OpenAI streaming providers. */
async function callPerplexityApi(
	config: ApiConfig,
	request: PerplexityRequest,
	fetchImpl: FetchImpl | undefined,
	signal?: AbortSignal,
	timeoutMs?: number,
): Promise<SearchResponse> {
	const metadata: PerplexityApiStreamMetadata = {};
	const context = buildPerplexityContext(request);
	const requestSignal = withHardTimeout(signal, timeoutMs);
	const onSseEvent = (event: { data: string }): void => {
		collectPerplexityMetadata(metadata, event.data);
	};

	const message = config.useResponses

View on GitHub (pinned to 9690622007)

Solutions

  1. Read the status and details embedded in the message to identify the upstream cause
  2. Verify the Perplexity API key and remaining credits
  3. If 429/402, wait or top up credits before retrying
  4. Retry with a supported model name if the model was rejected
Defensive patterns

Strategy: try-catch

Validate before calling

if (!process.env.PERPLEXITY_API_KEY) throw new Error('Perplexity API key missing');

Type guard

function isSearchProviderError(e: unknown): e is SearchProviderError {
  return e instanceof SearchProviderError;
}

Try / catch

try {
  return await perplexitySearch(params);
} catch (err) {
  if (err instanceof SearchProviderError && /Perplexity API error \((\d+)\)/.test(err.message)) {
    const status = Number(err.message.match(/\((\d+)\)/)?.[1]);
    if (status === 429 || status === 402) await retryLater();
  }
  throw err;
}

Prevention

When it happens

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

Common situations: Invalid or revoked Perplexity API key, exceeding monthly credits, requesting an unavailable model, OpenRouter key with insufficient balance.

Related errors


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