{"record":{"id":"f588205b89af9a83","repo":"can1357/oh-my-pi","slug":"ecosia-html-error-page-status","errorCode":null,"errorMessage":"Ecosia HTML error (${page.status})","messagePattern":"Ecosia HTML error \\((.+?)\\)","errorType":"exception","errorClass":"SearchProviderError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/web/search/providers/ecosia.ts","lineNumber":144,"sourceCode":"\t\tif (error instanceof SearchProviderError || params.signal?.aborted) throw error;\n\t\tif (signal.aborted) {\n\t\t\tthrow new SearchProviderError(\"ecosia\", \"Ecosia search timed out.\", 504);\n\t\t}\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tthrow new SearchProviderError(\"ecosia\", `Ecosia search failed: ${message}`, 503);\n\t}\n\n\tif (isBlockedPage(page)) {\n\t\tthrow new SearchProviderError(\n\t\t\t\"ecosia\",\n\t\t\t\"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.\",\n\t\t\t429,\n\t\t);\n\t}\n\tif (page.status < 200 || page.status >= 300) {\n\t\tconst classified = classifyProviderHttpError(\"ecosia\", page.status, page.html);\n\t\tif (classified) throw classified;\n\t\tthrow new SearchProviderError(\"ecosia\", `Ecosia HTML error (${page.status})`, page.status);\n\t}\n\treturn page.html;\n}\n\n/** Execute an Ecosia web search and parse the server-rendered result page. */\nexport async function searchEcosia(params: SearchParams): Promise<SearchResponse> {\n\tconst numResults = clampNumResults(params.numSearchResults ?? params.limit, DEFAULT_NUM_RESULTS, MAX_NUM_RESULTS);\n\tconst html = await callEcosiaHtml(params);\n\tconst parsed = parseHtmlResults(html);\n\n\tconst sources: SearchSource[] = [];\n\tconst seen = new Set<string>();\n\tfor (const result of parsed) {\n\t\tif (seen.has(result.url)) continue;\n\t\tseen.add(result.url);\n\t\tsources.push({ title: result.title, url: result.url, snippet: result.snippet });\n\t\tif (sources.length >= numResults) break;\n\t}","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/web/search/providers/ecosia.ts#L126-L162","documentation":"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.","triggerScenarios":"Ecosia returned an HTTP status outside 200-299 (e.g. 500, 502, 503) and classifyProviderHttpError had no specific classification for that status/body combination.","commonSituations":"Ecosia server-side outages or maintenance; intermediate proxy/CDN errors (502/504); unexpected 4xx statuses not covered by the classifier.","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."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  const res = await search({ provider: \"ecosia\", query });\n} catch (e) {\n  if (e instanceof SearchProviderError && e.status >= 500) {\n    await Bun.sleep(1000); // retry with backoff for transient server errors\n  } else throw e;\n}","preventionTips":["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"],"tags":["http","search-provider","ecosia","server-error"],"backgroundTag":"http-5xx-server-error","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}