can1357/oh-my-pi · warning · SearchProviderError
${provider.label} returned no renderable search content.
Error message
${provider.label} returned no renderable search content. What it means
After a provider responds, executeSearch validates that the response actually contains renderable content (results/text). If hasRenderableSearchContent returns false it throws SearchProviderError with status 204, meaning the provider answered but nothing usable came back — an empty or unusable payload, not a transport error.
Source
Thrown at packages/coding-agent/src/web/search/index.ts:240
// Lenient constraint pass over whatever the provider returned: enforce
// site:/inurl:/intitle:/filetype:/date directives the provider could
// not (or only partially) honor natively, relaxing any dimension that
// would wipe out every result. Citations/answer text stay untouched.
let finalResponse = response;
const constraintNotes: string[] = [];
if (parsedQuery.hasConstraints && response.sources.length > 0) {
const filtered = applyQueryConstraints(response.sources, parsedQuery);
if (filtered.sources.length !== response.sources.length) {
finalResponse = { ...response, sources: filtered.sources };
}
for (const label of filtered.dropped) {
constraintNotes.push(`no results matched \`${label}\`; the constraint was relaxed`);
}
}
if (!hasRenderableSearchContent(finalResponse)) {
throw new SearchProviderError(provider.id, `${provider.label} returned no renderable search content.`, 204);
}
const text = formatForLLM(finalResponse, constraintNotes);
return {
content: [{ type: "text" as const, text }],
details: { response: finalResponse },
};
} catch (error) {
// Surface user-initiated cancellation immediately so the session sees
// a clean abort instead of a generic "all providers failed" message.
// Without this, an AbortError from `fetch()` is treated as a provider
// failure and the loop falls through to the next provider (or to the
// summary error), masking the cancellation.
throwIfAborted(signal);
failures.push({ provider: provider ?? providerMeta, error });
}
}View on GitHub (pinned to 9690622007)
Solutions
- Broaden the query (fewer/shorter terms, remove site: filters).
- Relax include/exclude domain constraints that filtered out all results.
- Retry with the next provider in the chain instead of pinning one provider.
- Catch SearchProviderError with status 204 and fall back to another provider or report 'no results' to the model/user.
Example fix
// before
const res = await runSearchQuery({ query, provider: "brave", excludeDomains: many }, opts);
// after
try {
return await runSearchQuery({ query, provider: "brave" }, opts);
} catch (e) {
if (e instanceof SearchProviderError && e.status === 204) {
return await runSearchQuery({ query }, opts); // automatic chain fallback
}
throw e;
} Defensive patterns
Strategy: fallback
Validate before calling
// After receiving a response, before trusting it: if (!hasRenderableSearchContent(response)) return null; // trigger fallback
Type guard
null
Try / catch
try { return await executeSearchWith(providerId, params); }
catch (e) {
if (e instanceof SearchProviderError && e.status === 204) {
return await runSearchQuery(params, opts); // try next provider in chain
}
throw e;
} Prevention
- Relax include/exclude filters when they can plausibly drop all results.
- Don't hard-pin a single provider; allow chain fallback.
- Detect empty-result queries up front and set expectations (report 'no results' vs provider failure).
- Log the provider response summary when this fires to catch provider-side shape changes early.
When it happens
Trigger: A search provider returns HTTP 200 with an empty result set, only filtered-out results, or a payload shape that renders to nothing (e.g. all results dropped by domain/exclude constraints).
Common situations: Very niche query with zero hits; overly restrictive include/exclude filters dropping every result; provider API change degrading response shape; region/language restrictions returning empty results.
Related errors
- xAI device-code response was not a JSON object.
- xAI device-code response missing or invalid required fields.
- ${label} was not a JSON object
- ${label} missing expires_in
- Discord response did not include a message ID
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/631ec6c92901a97c.
Report an issue: GitHub.