{"record":{"id":"e288bca7eba91b51","repo":"can1357/oh-my-pi","slug":"mojeek-search-timed-out","errorCode":null,"errorMessage":"Mojeek search timed out.","messagePattern":"Mojeek search timed out\\.","errorType":"exception","errorClass":"SearchProviderError","httpStatus":504,"severity":"warning","filePath":"packages/coding-agent/src/web/search/providers/mojeek.ts","lineNumber":161,"sourceCode":"\ttry {\n\t\tpage = await browserFetch(url, {\n\t\t\tfetch: params.fetch,\n\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);","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/web/search/providers/mojeek.ts#L143-L179","documentation":"Thrown by callMojeekHtml when the fetch to Mojeek's HTML results page fails and the abort signal is aborted — i.e. the operation exceeded its timeout (or the caller cancelled) after the underlying error was not already a SearchProviderError. It surfaces as a SearchProviderError with status 504 (gateway timeout semantics).","triggerScenarios":"Mojeek fetch exceeds the configured timeout (retryDelayMs/timeout settings around the fetchWithRetry call) or the caller's signal aborts mid-flight, with no SearchProviderError already raised.","commonSituations":"Slow or congested network to mojeek.com; Mojeek slow to respond under load; overly tight timeout configuration; user cancels the search.","solutions":["Increase the timeout configured for the Mojeek fetch","Check network connectivity/latency to mojeek.com","Retry the search; Mojeek slowness is often transient","Respect the abort signal — if cancellation was intentional, propagate rather than retry"],"exampleFix":"// before\ncallMojeekHtml(params) // default timeout too tight\n// after\ncallMojeekHtml({ ...params, timeoutMs: 15_000 })","handlingStrategy":"retry","validationCode":"// ensure a sane timeout is configured upstream\nconst timeoutMs = params.timeoutMs ?? 15_000;","typeGuard":null,"tryCatchPattern":"try {\n  const res = await searchMojeek({ query, signal });\n} catch (err) {\n  if (err instanceof SearchProviderError && err.status === 504) {\n    // timeout: retry once with a longer timeout or fall back\n  } else throw err;\n}","preventionTips":["Set timeouts generous enough for HTML scraping (10-20s)","Pass an AbortSignal you actually control and check intent on abort","Retry once on 504 before failing over to another provider","Monitor latency to mojeek.com from your deployment environment"],"tags":["timeout","network","mojeek","abort"],"backgroundTag":"request-timeout","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}