can1357/oh-my-pi · error · SearchProviderError
Ecosia HTML error (${page.status})
Error message
Ecosia HTML error (${page.status}) What it means
Generic non-2xx HTTP status from the Ecosia HTML endpoint that was not classified into a more specific provider error. The provider first tries classifyProviderHttpError for a richer message; if that returns nothing, it throws this with the raw status code as both message and status.
Source
Thrown at packages/coding-agent/src/web/search/providers/ecosia.ts:144
if (error instanceof SearchProviderError || params.signal?.aborted) throw error;
if (signal.aborted) {
throw new SearchProviderError("ecosia", "Ecosia search timed out.", 504);
}
const message = error instanceof Error ? error.message : String(error);
throw new SearchProviderError("ecosia", `Ecosia search failed: ${message}`, 503);
}
if (isBlockedPage(page)) {
throw new SearchProviderError(
"ecosia",
"Ecosia blocked the request with a Cloudflare bot challenge. Ecosia's firewall throttles automated searches from datacenter/shared-egress IPs; try another web search provider such as DuckDuckGo, Brave, or Tavily.",
429,
);
}
if (page.status < 200 || page.status >= 300) {
const classified = classifyProviderHttpError("ecosia", page.status, page.html);
if (classified) throw classified;
throw new SearchProviderError("ecosia", `Ecosia HTML error (${page.status})`, page.status);
}
return page.html;
}
/** Execute an Ecosia web search and parse the server-rendered result page. */
export async function searchEcosia(params: SearchParams): Promise<SearchResponse> {
const numResults = clampNumResults(params.numSearchResults ?? params.limit, DEFAULT_NUM_RESULTS, MAX_NUM_RESULTS);
const html = await callEcosiaHtml(params);
const parsed = parseHtmlResults(html);
const sources: SearchSource[] = [];
const seen = new Set<string>();
for (const result of parsed) {
if (seen.has(result.url)) continue;
seen.add(result.url);
sources.push({ title: result.title, url: result.url, snippet: result.snippet });
if (sources.length >= numResults) break;
}View on GitHub (pinned to 9690622007)
Solutions
- Check Ecosia service status — a 5xx indicates a server-side problem on Ecosia's side.
- Retry with backoff; transient 502/503 responses usually resolve on their own.
- Switch to another search provider while Ecosia is degraded.
- Inspect the status code in the message to distinguish client (4xx) vs server (5xx) issues.
Defensive patterns
Strategy: retry
Try / catch
try {
const res = await search({ provider: "ecosia", query });
} catch (e) {
if (e instanceof SearchProviderError && e.status >= 500) {
await Bun.sleep(1000); // retry with backoff for transient server errors
} else throw e;
} Prevention
- Retry 5xx with exponential backoff; they are usually transient on Ecosia's side
- Do not retry 4xx statuses — fix the request instead
- Have a secondary provider configured for Ecosia outages
- Check Ecosia status/uptime before debugging your own code
When it happens
Trigger: Ecosia returned an HTTP status outside 200-299 (e.g. 500, 502, 503) and classifyProviderHttpError had no specific classification for that status/body combination.
Common situations: Ecosia server-side outages or maintenance; intermediate proxy/CDN errors (502/504); unexpected 4xx statuses not covered by the classifier.
Related errors
- Share upload to ${base} failed: HTTP ${res.status}${detail ?
- Anthropic API error (${response.status}): ${errorText}
- Ecosia search timed out.
- Ecosia search failed: ${message}
- Ecosia blocked the request with a Cloudflare bot challenge.
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/f588205b89af9a83.
Report an issue: GitHub.