can1357/oh-my-pi · error · SearchProviderError

Anthropic API error (${response.status}): ${errorText}

Error message

Anthropic API error (${response.status}): ${errorText}

What it means

The Anthropic search provider calls the Anthropic API; on a non-OK HTTP status it first tries classifyProviderHttpError to map known statuses to richer errors. If unclassified, it throws SearchProviderError carrying the raw status and response body text — the generic fallback for any API rejection (auth, rate limit, server error, malformed request).

Source

Thrown at packages/coding-agent/src/web/search/providers/anthropic.ts:220

	if (systemBlocks && systemBlocks.length > 0) {
		body.system = systemBlocks;
	}

	// OAuth requests inject the CC billing header (buildSystemBlocks); patch its
	// cch attestation like the streaming path instead of shipping `cch=00000`.
	const doFetch = auth.isOAuth ? wrapFetchForCch(fetchImpl) : fetchImpl;
	const response = await doFetch(url, {
		method: "POST",
		headers,
		body: JSON.stringify(body),
		signal: withHardTimeout(signal, timeoutMs),
	});

	if (!response.ok) {
		const errorText = await response.text();
		const classified = classifyProviderHttpError("anthropic", response.status, errorText);
		if (classified) throw classified;
		throw new SearchProviderError(
			"anthropic",
			`Anthropic API error (${response.status}): ${errorText}`,
			response.status,
		);
	}

	return response.json() as Promise<AnthropicApiResponse>;
}

/**
 * Parses a human-readable page age string into seconds.
 * @param pageAge - Age string like "2 days ago", "3h ago", "1 week ago"
 * @returns Age in seconds, or undefined if parsing fails
 */
function parsePageAge(pageAge: string | null | undefined): number | undefined {
	if (!pageAge) return undefined;

	const match = pageAge.match(/^(\d+)\s*(s|sec|second|m|min|minute|h|hour|d|day|w|week|mo|month|y|year)s?\s*(ago)?$/i);

View on GitHub (pinned to 9690622007)

Solutions

  1. Read the embedded status and errorText to identify root cause (401 → fix key, 429 → back off, 5xx → retry later).
  2. Verify/rotate the Anthropic API key in auth storage.
  3. Catch SearchProviderError and fall back to another search provider in the chain.
  4. Add retry with exponential backoff for 429/5xx statuses before surfacing the failure.

Example fix

// before
const res = await runSearchQuery({ query, provider: "anthropic" }, opts);
// after
try {
  return await runSearchQuery({ query, provider: "anthropic" }, opts);
} catch (e) {
  if (e instanceof SearchProviderError && (e.status === 429 || (e.status ?? 500) >= 500)) {
    await Bun.sleep(2000);
    return await runSearchQuery({ query }, opts); // retry / fallback chain
  }
  throw e;
}
Defensive patterns

Strategy: fallback

Validate before calling

// Pre-flight: verify credentials exist before making the call
const provider = await getSearchProvider("anthropic");
if (!(await provider.isAvailable(authStorage))) {
  throw new Error("Anthropic credentials missing/invalid — configure before searching");
}

Type guard

null

Try / catch

try { return await searchWith("anthropic", params); }
catch (e) {
  if (e instanceof SearchProviderError && typeof e.status === "number") {
    if (e.status === 429 || e.status >= 500) return await searchWithAutomatic(params); // retryable
    if (e.status === 401 || e.status === 403) throw new Error("Fix Anthropic credentials");
  }
  throw e;
}

Prevention

When it happens

Trigger: Anthropic API returns 401/403 (bad key), 429 (rate limit), 5xx (outage), or 400 (bad request) and the error classifier doesn't produce a specialized error.

Common situations: Expired or revoked ANTHROPIC_API_KEY; account out of credits; org blocked for web search; Anthropic incident/outage; request exceeding rate limits under parallel tool calls.

Related errors


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