{"record":{"id":"8195243af2890dc0","repo":"can1357/oh-my-pi","slug":"mojeek-html-error-page-status","errorCode":null,"errorMessage":"Mojeek HTML error (${page.status})","messagePattern":"Mojeek HTML error \\((.+?)\\)","errorType":"exception","errorClass":"SearchProviderError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/web/search/providers/mojeek.ts","lineNumber":181,"sourceCode":"\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}\n\treturn page.html;\n}\n\n/** Execute a Mojeek web search against the standard HTML results page. */\nexport async function searchMojeek(params: SearchParams): Promise<SearchResponse> {\n\tconst numResults = clampNumResults(params.numSearchResults ?? params.limit, DEFAULT_NUM_RESULTS, MAX_NUM_RESULTS);\n\tconst html = await callMojeekHtml(params, numResults);\n\tconst parsed = parseHtmlResults(html);\n\n\tconst sources: SearchSource[] = [];\n\tconst seen = new Set<string>();\n\tfor (const result of parsed) {\n\t\tif (seen.has(result.url)) continue;\n\t\tseen.add(result.url);\n\t\tsources.push({ title: result.title, url: result.url, snippet: result.snippet });\n\t\tif (sources.length >= numResults) break;\n\t}","sourceCodeStart":163,"sourceCodeEnd":199,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/web/search/providers/mojeek.ts#L163-L199","documentation":"Thrown by callMojeekHtml when Mojeek returns an HTTP status outside 2xx that is not a robot wall and not classified by classifyProviderHttpError. The status is attached to the SearchProviderError; the message is simply 'Mojeek HTML error (<status>)'.","triggerScenarios":"Mojeek HTML endpoint returns e.g. 500/502/503 (server issues) or an unclassified 4xx, with page content that does not match isRobotPage.","commonSituations":"Mojeek server-side incidents; maintenance windows returning 5xx; unclassified 403/405 variants; intermittent upstream failures.","solutions":["Check the attached status (err.status) — 5xx means retry with backoff","Check Mojeek's service status for outages","Reduce request rate if seeing repeated 4xx/5xx","Update classifyProviderHttpError if this status should map to a richer classified error"],"exampleFix":"// before\nconst results = await searchMojeek({ query });\n// after\ntry {\n  const results = await searchMojeek({ query });\n} catch (err) {\n  if (err instanceof SearchProviderError && (err.status ?? 0) >= 500) {\n    // transient Mojeek outage — retry or use fallback provider\n  }\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  const res = await searchMojeek({ query });\n} catch (err) {\n  if (err instanceof SearchProviderError && err.message.startsWith('Mojeek HTML error (5')) {\n    await Bun.sleep(2000); // transient server error: bounded retry\n  } else throw err;\n}","preventionTips":["Retry only 5xx statuses with capped exponential backoff","Check Mojeek status before concluding a persistent failure","Fail over to another provider after N consecutive server errors","Extend classifyProviderHttpError when new statuses appear repeatedly"],"tags":["http","mojeek","server-error","html"],"backgroundTag":"http-5xx-server-error","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}