can1357/oh-my-pi · error · SearchProviderError

DuckDuckGo HTML error (${page.status})

Error message

DuckDuckGo HTML error (${page.status})

What it means

callDuckDuckGoHtml POSTs the query to DuckDuckGo's html.duckduckgo.com frontend via browserFetch. Any non-2xx status that classifyProviderHttpError cannot map to a more specific error becomes a SearchProviderError carrying the raw HTTP status, so callers can react to rate limits, outages, or gateway errors from the HTML endpoint.

Source

Thrown at packages/coding-agent/src/web/search/providers/duckduckgo.ts:321

async function callDuckDuckGoHtml(params: SearchParams, form: URLSearchParams, signal: AbortSignal): Promise<string> {
	const page = await browserFetch(DUCKDUCKGO_HTML_URL, {
		fetch: params.fetch ?? fetch,
		signal,
		timeoutMs: params.timeoutMs,
		referer: "https://html.duckduckgo.com/",
		init: {
			method: "POST",
			body: form.toString(),
		},
		headers: { "Content-Type": "application/x-www-form-urlencoded" },
	});

	const body = page.html;
	if (page.status < 200 || page.status >= 300) {
		const classified = classifyProviderHttpError("duckduckgo", page.status, body);
		if (classified) throw classified;
		throw new SearchProviderError("duckduckgo", `DuckDuckGo HTML error (${page.status})`, page.status);
	}

	if (isAnomalyResponse(body)) {
		throw new SearchProviderError(
			"duckduckgo",
			"DuckDuckGo blocked the request with a bot-detection challenge. DuckDuckGo throttles automated HTML searches from datacenter/shared-egress IPs; configure a credentialed provider such as Brave, Tavily, Exa, or Kagi for reliable web search.",
			429,
		);
	}

	return body;
}

/** Execute a DuckDuckGo web search via the no-JS HTML frontend. */
export async function searchDuckDuckGo(params: SearchParams): Promise<SearchResponse> {
	const numResults = clampNumResults(params.numSearchResults ?? params.limit, DEFAULT_NUM_RESULTS, MAX_NUM_RESULTS);
	const signal = withHardTimeout(params.signal, params.timeoutMs);
	const sources: SearchSource[] = [];

View on GitHub (pinned to 9690622007)

Solutions

  1. Retry with backoff — many 5xx statuses are transient.
  2. Check the numeric status in the message: 429-style throttling means switch egress IP or use a credentialed provider.
  3. Fall back to another provider (Brave, Tavily, Exa, Kagi) via the provider chain.
  4. Verify network/proxy is not intercepting html.duckduckgo.com with an error page.

Example fix

// before
const res = await searchDuckDuckGo(params); // hard failure on 503
// after
try {
  return await searchDuckDuckGo(params);
} catch (e) {
  if (e instanceof SearchProviderError && (e.status ?? 0) >= 500) return retryWithBackoff(() => searchDuckDuckGo(params));
  throw e;
}
Defensive patterns

Strategy: retry

Type guard

function isDuckDuckGoHttpError(e: unknown): e is SearchProviderError {
  return e instanceof SearchProviderError && e.provider === "duckduckgo" && /^DuckDuckGo HTML error \(\d+\)$/.test(e.message);
}

Try / catch

try {
  return await searchDuckDuckGo(params);
} catch (e) {
  if (isDuckDuckGoHttpError(e)) {
    const status = e.status ?? 0;
    if (status >= 500 || status === 408) return retryWithBackoff(() => searchDuckDuckGo(params), 3);
    if (status === 429) return fallbackProvider(params);
  }
  throw e;
}

Prevention

When it happens

Trigger: browserFetch returns a page with status outside 200–299 and classifyProviderHttpError("duckduckgo", status, body) returns undefined — e.g. unusual statuses (408, 500-series) or bodies not matching known block patterns.

Common situations: DuckDuckGo temporary outages or 5xx errors; datacenter IP rate limiting with a status not matching the anomaly page; corporate proxies returning gateway errors; DDG changing response codes for automated traffic.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


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