can1357/oh-my-pi · error · SearchProviderError

Ecosia search timed out.

Error message

Ecosia search timed out.

What it means

callEcosiaHtml wraps browserFetch of Ecosia's search page in a hard-timeout signal. If the underlying fetch or render-wait throws and neither the outer params.signal nor a prior SearchProviderError explains it, a signal.aborted check distinguishes timeouts: it throws a SearchProviderError with status 504 when the composed hard-timeout signal fired.

Source

Thrown at packages/coding-agent/src/web/search/providers/ecosia.ts:128

	try {
		page = await browserFetch(url.href, {
			fetch: params.fetch,
			signal,
			timeoutMs: params.timeoutMs,
			referer: ECOSIA_HOME_URL,
			browser: {
				homeUrl: ECOSIA_HOME_URL,
				ready: {
					selector: 'article[data-test-id="organic-result"]',
					timeoutMs: RESULT_RENDER_TIMEOUT_MS,
				},
				shouldFallback: isBlockedPage,
			},
		});
	} catch (error) {
		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;

View on GitHub (pinned to 9690622007)

Solutions

  1. Increase timeoutMs in the search params to accommodate Ecosia's JS render time.
  2. Retry — transient slowness often resolves; the provider chain may also fall back.
  3. Check network connectivity/latency to ecosia.com from the running environment.
  4. Switch to a faster or API-backed provider (Brave, Tavily) for latency-sensitive workloads.

Example fix

// before
await search({ provider: "ecosia", query, timeoutMs: 5000 }); // render wait exceeds 5s
// after
await search({ provider: "ecosia", query, timeoutMs: 20000 });
Defensive patterns

Strategy: retry

Validate before calling

// pre-call sanity: ensure the timeout budget is realistic
if (params.timeoutMs < 10000) console.warn("Ecosia HTML render typically needs >10s; low timeoutMs risks 504");

Type guard

function isEcosiaTimeout(e: unknown): e is SearchProviderError {
  return e instanceof SearchProviderError && e.provider === "ecosia" && e.status === 504 && e.message === "Ecosia search timed out.";
}

Try / catch

try {
  return await searchEcosia(params);
} catch (e) {
  if (isEcosiaTimeout(e)) return retryWithBackoff(() => searchEcosia({ ...params, timeoutMs: 20000 }));
  if (e instanceof SearchProviderError && e.status === 429) return fallbackProvider(params);
  throw e;
}

Prevention

When it happens

Trigger: browserFetch (including the result-render wait for `article[data-test-id="organic-result"]`) exceeds params.timeoutMs, aborting the withHardTimeout signal; the original error is then replaced by this 504 timeout error.

Common situations: Slow Ecosia page renders (Cloudflare interstitials delaying content); too-small timeoutMs passed in SearchParams; network latency to Ecosia; JS-render wait never matching the result selector after a page layout change.

Understand the failure class

Related errors


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