can1357/oh-my-pi · error · SearchProviderError

Perplexity ask stream error: ${message}

Error message

Perplexity ask stream error: ${message}

What it means

While consuming the Perplexity ask SSE stream, an event carried an error_code field, meaning Perplexity aborted the answer mid-stream. The provider throws a SearchProviderError (status 400) whose message is the stream's error_message, or the raw error_code when no human-readable message was supplied.

Source

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

			`Perplexity ask API error (${response.status}): ${errorText}`,
			response.status,
		);
	}

	if (!response.body) {
		throw new SearchProviderError("perplexity", "Perplexity ask API returned no response body", 500);
	}

	let answer = "";
	let model: string | undefined;
	let finalRequestId: string | undefined;
	const sourcesByUrl = new Map<string, SearchSource>();
	let mergedEvent: PerplexityOAuthStreamEvent = { blocks: [] };

	for await (const event of readSseJson<PerplexityOAuthStreamEvent>(response.body, params.signal)) {
		if (event.error_code) {
			const message = event.error_message ?? event.error_code;
			throw new SearchProviderError("perplexity", `Perplexity ask stream error: ${message}`, 400);
		}

		mergedEvent = mergeOAuthEventSnapshot(mergedEvent, event);

		const eventAnswer = buildOAuthAnswer(mergedEvent);
		if (eventAnswer.length > 0) {
			answer = eventAnswer;
		}
		for (const source of buildOAuthSources(mergedEvent)) {
			sourcesByUrl.set(oauthSourceKey(source.url), source);
		}

		const reportedModel = [mergedEvent.user_selected_model, mergedEvent.display_model].find(
			candidate => candidate && candidate !== "turbo",
		);
		if (reportedModel) model = reportedModel;
		if (mergedEvent.uuid) finalRequestId = mergedEvent.uuid;
		if (mergedEvent.final || mergedEvent.status === "COMPLETED") {

View on GitHub (pinned to 9690622007)

Solutions

  1. Read error_code/error_message in the message to identify the cause
  2. If auth-related, refresh the Perplexity OAuth token or supply valid cookies
  3. Rephrase or simplify the query if it was rejected by filters
  4. Retry; mid-stream upstream failures are often transient
Defensive patterns

Strategy: try-catch

Validate before calling

// verify a fresh session exists before streaming
if (!hasFreshOAuthSession("perplexity")) await loginPerplexityOAuth();

Type guard

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

Try / catch

try {
  return await perplexityAsk(params);
} catch (err) {
  if (err instanceof SearchProviderError && err.message.includes("ask stream error")) {
    // auth codes -> re-login; otherwise transient -> retry or fall back
  }
  throw err;
}

Prevention

When it happens

Trigger: readSseJson yields a PerplexityOAuthStreamEvent with error_code set during callPerplexityAsk's for-await loop — e.g. invalid/expired OAuth token, query rejected by moderation, or upstream processing failure.

Common situations: Expired Perplexity OAuth access token, anonymous access blocked, queries that trip Perplexity's content filters, transient upstream model failures mid-stream.

Related errors


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