{"record":{"id":"a5484412b86dcde1","repo":"can1357/oh-my-pi","slug":"mojeek-search-failed-message","errorCode":null,"errorMessage":"Mojeek search failed: ${message}","messagePattern":"Mojeek search failed: (.+?)","errorType":"exception","errorClass":"SearchProviderError","httpStatus":503,"severity":"error","filePath":"packages/coding-agent/src/web/search/providers/mojeek.ts","lineNumber":164,"sourceCode":"\t\t\tsignal,\n\t\t\ttimeoutMs: params.timeoutMs,\n\t\t\trandomizeHeaders: false,\n\t\t\treferer: MOJEEK_HOME_URL,\n\t\t\tbrowser: {\n\t\t\t\thomeUrl: MOJEEK_HOME_URL,\n\t\t\t\tafterNavigation: solveCaptcha,\n\t\t\t\tshouldFallback: isRobotPage,\n\t\t\t\tattempts: 2,\n\t\t\t\tretryDelayMs: 1_000,\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(\"mojeek\", \"Mojeek search timed out.\", 504);\n\t\t}\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tthrow new SearchProviderError(\"mojeek\", `Mojeek search failed: ${message}`, 503);\n\t}\n\n\t// Robot walls: the ALTCHA proof-of-work captcha page arrives as HTTP 200\n\t// (`<title>Captcha</title>`, `altcha-widget`) and the \"automated queries\"\n\t// refusal as HTTP 403. Both bodies are more actionable than their raw\n\t// statuses, so check them before the generic status handling.\n\tif (isRobotPage(page)) {\n\t\tthrow new SearchProviderError(\n\t\t\t\"mojeek\",\n\t\t\t\"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.\",\n\t\t\t429,\n\t\t);\n\t}\n\tif (page.status < 200 || page.status >= 300) {\n\t\tconst classified = classifyProviderHttpError(\"mojeek\", page.status, page.html);\n\t\tif (classified) throw classified;\n\t\tthrow new SearchProviderError(\"mojeek\", `Mojeek HTML error (${page.status})`, page.status);\n\t}","sourceCodeStart":146,"sourceCodeEnd":182,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/web/search/providers/mojeek.ts#L146-L182","documentation":"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).","triggerScenarios":"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.","commonSituations":"Offline machine or blocked egress to mojeek.com; corporate proxy intercepting TLS; Mojeek temporarily unreachable; bugs in HTML parsing after Mojeek markup changes.","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"],"exampleFix":"// before\nconst results = await searchMojeek({ query });\n// after\ntry {\n  const results = await searchMojeek({ query });\n} catch (err) {\n  if (err instanceof SearchProviderError) {\n    console.error(`Mojeek root cause: ${err.message}`);\n    // fall back to another provider\n  }\n}","handlingStrategy":"fallback","validationCode":"// basic connectivity preflight\nconst reachable = await fetch('https://www.mojeek.com', { method: 'HEAD' }).then(r => r.ok).catch(() => false);\nif (!reachable) skipMojeek();","typeGuard":null,"tryCatchPattern":"try {\n  const res = await searchMojeek({ query });\n} catch (err) {\n  if (err instanceof SearchProviderError && err.message.startsWith('Mojeek search failed:')) {\n    return fallbackProvider(query); // DNS/TLS/network-level failure\n  }\n  throw err;\n}","preventionTips":["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"],"tags":["network","fetch","mojeek","error-wrapping"],"backgroundTag":"network-request-failed","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}