can1357/oh-my-pi · error · SearchProviderError

${err.message}

Error message

${err.message}

What it means

Re-thrown by searchKagi as a SearchProviderError wrapping a KagiApiError whose statusCode is not classified by classifyProviderHttpError (i.e. an unexceptional or unusual HTTP status). The original Kagi error message is preserved verbatim.

Solutions

  1. Read err.status (the wrapped statusCode) and err.message for the actual Kagi failure reason
  2. Check your Kagi API key balance/subscription if the message indicates payment or quota
  3. Retry with backoff for 5xx-class statuses
  4. Add the unclassified status to classifyProviderHttpError if it should map to a richer error

Example fix

// before
const results = await searchKagi({ query, authStorage });
// after
try {
  const results = await searchKagi({ query, authStorage });
} catch (err) {
  if (err instanceof SearchProviderError && err.status === 402) {
    // Kagi subscription issue — check billing
  }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// preflight: verify Kagi key works with a cheap call
const ok = await fetch('https://kagi.com/api/v0/search?q=test', { headers: { Authorization: `Bot ${key}` } }).then(r => r.status !== 401);

Type guard

function isKagiApiError(e: unknown): e is { name: 'KagiApiError'; statusCode?: number; message: string } {
  return e instanceof Error && e.name === 'KagiApiError';
}

Try / catch

try {
  const res = await searchKagi({ query, authStorage });
} catch (err) {
  if (err instanceof SearchProviderError && typeof err.status === 'number') {
    if (err.status === 402) handleBilling();
    else if (err.status >= 500) retryWithBackoff();
    else throw err;
  } else throw err;
}

Prevention

When it happens

Trigger: Kagi API request fails with a KagiApiError carrying a numeric statusCode that classifyProviderHttpError does not map (e.g. 4xx/5xx statuses outside the classified set like 402, 418, 520), so the raw error is wrapped and thrown.

Common situations: Kagi billing/quota states (402 payment required), unusual upstream errors behind Kagi, novel status codes not yet in the classification table.

Related errors


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

Appendix: source

Thrown at packages/coding-agent/src/web/search/providers/kagi.ts:68

				fetch: params.fetch,
			},
			params.authStorage,
		);

		return {
			provider: "kagi",
			sources: toSearchSources(result.sources, numResults),
			relatedQuestions: result.relatedQuestions.length > 0 ? result.relatedQuestions : undefined,
			requestId: result.requestId,
			answer: result.answer,
		};
	} catch (err) {
		if (err instanceof KagiApiError) {
			if (typeof err.statusCode === "number") {
				const classified = classifyProviderHttpError("kagi", err.statusCode, err.message);
				if (classified) throw classified;
			}
			throw new SearchProviderError("kagi", err.message, err.statusCode);
		}
		throw err;
	}
}

/** Search provider for Kagi web search. */
export class KagiProvider extends SearchProvider {
	readonly id = "kagi";
	readonly label = "Kagi";

	isAvailable(authStorage: AuthStorage): boolean {
		return authStorage.hasAuth("kagi");
	}

	search(params: SearchParamsWithFetch): Promise<SearchResponse> {
		const fetchImpl = params.fetch;

		return searchKagi({

View on GitHub (pinned to 9690622007)