can1357/oh-my-pi · error · SearchProviderError
Google returned its JavaScript challenge instead of rendered
Error message
Google returned its JavaScript challenge instead of rendered search results.
What it means
Thrown by callGoogleHtml when the page loads with a 2xx status but its HTML contains the '/httpservice/retry/enablejs' marker with no <h3> result headings — Google served its JavaScript challenge/consent page instead of rendered results. The headless-browser fallback that should execute Google's JS either did not run, failed, or still got the no-JS page.
Source
Thrown at packages/coding-agent/src/web/search/providers/google.ts:156
throw new SearchProviderError("google", "Google browser search timed out.", 504);
}
const message = error instanceof Error ? error.message : String(error);
throw new SearchProviderError("google", `Google browser search failed: ${message}`, 503);
}
const blocked = blockReason(page);
if (blocked === "traffic") {
throw new SearchProviderError(
"google",
"Google blocked the browser search with an automated-traffic challenge. Try another web search provider or retry later.",
429,
);
}
if (page.status < 200 || page.status >= 300) {
throw new SearchProviderError("google", `Google HTML error (${page.status})`, page.status);
}
if (blocked === "javascript") {
throw new SearchProviderError(
"google",
"Google returned its JavaScript challenge instead of rendered search results.",
429,
);
}
return page.html;
}
/** Execute a Google web search with fetch-first loading and a headless-browser fallback. */
export async function searchGoogle(params: SearchParams): Promise<SearchResponse> {
const numResults = clampNumResults(params.numSearchResults ?? params.limit, DEFAULT_NUM_RESULTS, MAX_NUM_RESULTS);
const html = await callGoogleHtml(params, numResults);
const parsed = parseHtmlResults(html);
const sources: SearchSource[] = [];
const seen = new Set<string>();
for (const result of parsed) {
if (seen.has(result.url)) continue;View on GitHub (pinned to 9690622007)
Solutions
- Ensure the headless browser runtime is installed so the browser fallback can render the JS challenge.
- Retry later — Google serves the challenge inconsistently.
- Switch to an API-backed search provider (Jina, Gemini) which is not affected by JS challenges.
- Update the package; detection and fallback heuristics are maintained against Google changes.
Example fix
# before: minimal image without browser FROM node:22-slim # after: include browser deps for the fallback FROM node:22-slim RUN npx playwright install --with-deps chromium
Defensive patterns
Strategy: fallback
Type guard
function isJsChallenge(e: unknown): boolean {
return e instanceof SearchProviderError && e.provider === 'google'
&& e.statusCode === 429 && e.message.includes('JavaScript challenge');
} Try / catch
try {
return await search({ provider: 'google', query });
} catch (err) {
if (isJsChallenge(err)) return await search({ provider: 'jina', query });
throw err;
} Prevention
- Ensure the headless browser fallback is installed so JS challenges can render.
- Handle EU/consent-wall regions via an API-backed provider.
- Watch for the challenge marker in logs to detect when Google tightens bot detection.
- Update the package when Google changes challenge heuristics.
When it happens
Trigger: fetch-first path received the enablejs page and the headless-browser fallback was unavailable, timed out at the `a h3` ready selector, or itself returned a page matching blockReason === 'javascript'; page.status is 2xx and not a traffic block.
Common situations: Headless browser not installed in the environment (fallback skipped or broken); consent-wall regions (e.g. EU cookie consent variants); Google A/B serving the JS challenge to plain fetch clients.
Related errors
- Google blocked the browser search with an automated-traffic
- Google HTML error (${page.status})
- Ecosia search failed: ${message}
- Google browser search timed out.
- Google browser search failed: ${message}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/920330645b5a6581.
Report an issue: GitHub.