can1357/oh-my-pi · error · SearchProviderError
Mojeek search failed: ${message}
Error message
Mojeek search failed: ${message} What it means
Generic failure wrapper in callMojeekHtml: any non-SearchProviderError thrown during the Mojeek fetch (DNS failure, connection refused, TLS error, HTML parse error) is re-thrown as a SearchProviderError with the underlying message appended and status 503 (service unavailable semantics).
Source
Thrown at packages/coding-agent/src/web/search/providers/mojeek.ts:164
signal,
timeoutMs: params.timeoutMs,
randomizeHeaders: false,
referer: MOJEEK_HOME_URL,
browser: {
homeUrl: MOJEEK_HOME_URL,
afterNavigation: solveCaptcha,
shouldFallback: isRobotPage,
attempts: 2,
retryDelayMs: 1_000,
},
});
} catch (error) {
if (error instanceof SearchProviderError || params.signal?.aborted) throw error;
if (signal.aborted) {
throw new SearchProviderError("mojeek", "Mojeek search timed out.", 504);
}
const message = error instanceof Error ? error.message : String(error);
throw new SearchProviderError("mojeek", `Mojeek search failed: ${message}`, 503);
}
// Robot walls: the ALTCHA proof-of-work captcha page arrives as HTTP 200
// (`<title>Captcha</title>`, `altcha-widget`) and the "automated queries"
// refusal as HTTP 403. Both bodies are more actionable than their raw
// statuses, so check them before the generic status handling.
if (isRobotPage(page)) {
throw new SearchProviderError(
"mojeek",
"Mojeek blocked the request with its automated-queries wall. Mojeek rate-limits scripted searches from datacenter/shared-egress IPs; retry later or configure another provider such as Brave, Tavily, Exa, or Kagi.",
429,
);
}
if (page.status < 200 || page.status >= 300) {
const classified = classifyProviderHttpError("mojeek", page.status, page.html);
if (classified) throw classified;
throw new SearchProviderError("mojeek", `Mojeek HTML error (${page.status})`, page.status);
}View on GitHub (pinned to 9690622007)
Solutions
- Read the embedded underlying message (after 'Mojeek search failed:') for the root cause
- Verify network egress to https://www.mojeek.com (DNS, proxy, firewall)
- Retry with backoff — 503 signals a transient condition
- Update Mojeek HTML parsing if the underlying message indicates a parse failure after a markup change
Example fix
// before
const results = await searchMojeek({ query });
// after
try {
const results = await searchMojeek({ query });
} catch (err) {
if (err instanceof SearchProviderError) {
console.error(`Mojeek root cause: ${err.message}`);
// fall back to another provider
}
} Defensive patterns
Strategy: fallback
Validate before calling
// basic connectivity preflight
const reachable = await fetch('https://www.mojeek.com', { method: 'HEAD' }).then(r => r.ok).catch(() => false);
if (!reachable) skipMojeek(); Try / catch
try {
const res = await searchMojeek({ query });
} catch (err) {
if (err instanceof SearchProviderError && err.message.startsWith('Mojeek search failed:')) {
return fallbackProvider(query); // DNS/TLS/network-level failure
}
throw err;
} Prevention
- Verify egress/DNS/proxy settings for mojeek.com in your environment
- Maintain a fallback provider chain (Brave, Tavily, Kagi)
- Retry transient 503s with backoff before failing over
- Update HTML parsing when the embedded message indicates markup changes
When it happens
Trigger: The fetch/parse pipeline throws a plain Error — DNS resolution failure, connection reset, certificate error, or an internal parse crash — and the signal is not aborted.
Common situations: Offline machine or blocked egress to mojeek.com; corporate proxy intercepting TLS; Mojeek temporarily unreachable; bugs in HTML parsing after Mojeek markup changes.
Related errors
- AnthropicConnectionError
- AnthropicConnectionTimeoutError
- xAI device-code request failed: ${error instanceof Error ? e
- Failed to fetch Umans models info
- Gemini Files API delete request failed
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/a5484412b86dcde1.
Report an issue: GitHub.