{"record":{"id":"9d5f4fcc3a80503e","repo":"can1357/oh-my-pi","slug":"ecosia-search-failed-message","errorCode":null,"errorMessage":"Ecosia search failed: ${message}","messagePattern":"Ecosia search failed: (.+?)","errorType":"exception","errorClass":"SearchProviderError","httpStatus":503,"severity":"error","filePath":"packages/coding-agent/src/web/search/providers/ecosia.ts","lineNumber":131,"sourceCode":"\t\t\tsignal,\n\t\t\ttimeoutMs: params.timeoutMs,\n\t\t\treferer: ECOSIA_HOME_URL,\n\t\t\tbrowser: {\n\t\t\t\thomeUrl: ECOSIA_HOME_URL,\n\t\t\t\tready: {\n\t\t\t\t\tselector: 'article[data-test-id=\"organic-result\"]',\n\t\t\t\t\ttimeoutMs: RESULT_RENDER_TIMEOUT_MS,\n\t\t\t\t},\n\t\t\t\tshouldFallback: isBlockedPage,\n\t\t\t},\n\t\t});\n\t} catch (error) {\n\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. */","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/web/search/providers/ecosia.ts#L113-L149","documentation":"Thrown as a SearchProviderError from the Ecosia HTML scraping provider when any unexpected exception occurs during the search request/parsing pipeline. It is a catch-all wrapper: the original error's message (network failure, HTML parse failure, etc.) is embedded into 'Ecosia search failed: <message>'. Timeouts and aborts are handled separately with dedicated codes, so this indicates a non-timeout, non-abort failure.","triggerScenarios":"Any exception thrown inside callEcosiaHtml that is not a SearchProviderError and not an abort: fetch failing with connection reset/DNS failure, TLS errors, or the HTML result parser throwing on malformed markup. Signal aborted cases and timeouts are routed to other branches.","commonSituations":"Corporate proxies or firewalls resetting connections to ecosia.org; transient DNS failures; Ecosia changing its HTML markup so the scraper's extraction code throws; running in an environment without outbound network access.","solutions":["Check outbound network connectivity to https://www.ecosia.org from the machine running the agent (curl -v https://www.ecosia.org).","Read the embedded <message> for the root cause and fix that underlying issue (DNS, proxy, TLS).","Switch to a JSON-API-based provider (DuckDuckGo, Brave, Tavily) which is less fragile than HTML scraping.","Retry once after a short delay if the underlying message suggests a transient network fault."],"exampleFix":"// before\nconst results = await search({ provider: \"ecosia\", query });\n// after\ntry {\n  const results = await search({ provider: \"ecosia\", query });\n} catch (e) {\n  if (e instanceof SearchProviderError && e.provider === \"ecosia\") {\n    const results = await search({ provider: \"duckduckgo\", query }); // fallback\n  } else throw e;\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"function isSearchProviderError(e: unknown): e is SearchProviderError {\n  return e instanceof SearchProviderError;\n}","tryCatchPattern":"try {\n  const res = await search({ provider: \"ecosia\", query });\n} catch (e) {\n  if (e instanceof SearchProviderError && e.provider === \"ecosia\") {\n    // inspect e.message for the root cause; fall back to another provider\n  } else throw e;\n}","preventionTips":["Verify outbound connectivity to ecosia.org before relying on this provider in deployments","Prefer JSON-API providers (Brave, Tavily) over HTML scraping for production","Add a fallback provider chain so single-provider failures degrade gracefully","Monitor the embedded root-cause message to distinguish network vs markup changes"],"tags":["network","search-provider","ecosia","scraping"],"backgroundTag":"http-request-failed","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}