can1357/oh-my-pi · error · SearchProviderError

Mojeek HTML error (${page.status})

Error message

Mojeek HTML error (${page.status})

What it means

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>)'.

Source

Thrown at packages/coding-agent/src/web/search/providers/mojeek.ts:181

		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);
	}
	return page.html;
}

/** Execute a Mojeek web search against the standard HTML results page. */
export async function searchMojeek(params: SearchParams): Promise<SearchResponse> {
	const numResults = clampNumResults(params.numSearchResults ?? params.limit, DEFAULT_NUM_RESULTS, MAX_NUM_RESULTS);
	const html = await callMojeekHtml(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;
		seen.add(result.url);
		sources.push({ title: result.title, url: result.url, snippet: result.snippet });
		if (sources.length >= numResults) break;
	}

View on GitHub (pinned to 9690622007)

Solutions

  1. Check the attached status (err.status) — 5xx means retry with backoff
  2. Check Mojeek's service status for outages
  3. Reduce request rate if seeing repeated 4xx/5xx
  4. Update classifyProviderHttpError if this status should map to a richer classified error

Example fix

// before
const results = await searchMojeek({ query });
// after
try {
  const results = await searchMojeek({ query });
} catch (err) {
  if (err instanceof SearchProviderError && (err.status ?? 0) >= 500) {
    // transient Mojeek outage — retry or use fallback provider
  }
}
Defensive patterns

Strategy: retry

Try / catch

try {
  const res = await searchMojeek({ query });
} catch (err) {
  if (err instanceof SearchProviderError && err.message.startsWith('Mojeek HTML error (5')) {
    await Bun.sleep(2000); // transient server error: bounded retry
  } else throw err;
}

Prevention

When it happens

Trigger: Mojeek HTML endpoint returns e.g. 500/502/503 (server issues) or an unclassified 4xx, with page content that does not match isRobotPage.

Common situations: Mojeek server-side incidents; maintenance windows returning 5xx; unclassified 403/405 variants; intermittent upstream failures.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/8195243af2890dc0. Report an issue: GitHub.