thedotmack/claude-mem · error

classifyGeminiError( )

Error message

classifyGeminiError({ cause: err })

What it means

In GeminiProvider.queryGeminiMultiTurn, any failure thrown by fetchGenerateContent — DNS resolution errors, connection resets, TLS failures, timeouts, or AbortSignal aborts — is wrapped via classifyGeminiError into a structured error object before propagating to the caller. classifyGeminiError inspects the cause and attaches a classification (e.g. network vs abort vs rate limit) used for retry and user-facing messaging.

Solutions

  1. Catch the classified error in the caller and check its classification before retrying
  2. Retry network-classified failures with backoff; respect any retry-after data attached by the classifier
  3. Check connectivity/proxy settings (HTTPS_PROXY) for persistent connection failures
  4. Distinguish abort errors (user intent) from network errors and do not auto-retry aborts

Example fix

// before
const text = await provider.query(messages);
// after
try {
  const text = await provider.query(messages);
} catch (e) {
  if ((e as GeminiError).classification === 'network') await backoffRetry(() => provider.query(messages));
  else throw e;
}
Defensive patterns

Strategy: retry

Validate before calling

// Before calling, verify connectivity and endpoint reachability
if (typeof navigator !== 'undefined' && navigator.onLine === false) {
  throw new Error('offline: skip Gemini query until network returns');
}

Type guard

const isNetworkClassified = (e: unknown): e is { classification: 'network'; cause: Error } =>
  typeof e === 'object' && e !== null && (e as any).classification === 'network';

Try / catch

try {
  const text = await provider.query(messages);
} catch (e) {
  if (isNetworkClassified(e) && !isAbortError(e.cause)) {
    return backoffRetry(() => provider.query(messages), { retries: 3 });
  }
  throw e;
}

Prevention

When it happens

Trigger: The fetch to the Gemini generateContent endpoint fails before an HTTP response exists: network outage, DNS failure, connection refused/reset, request aborted via attemptSignal, or fetch throwing for a malformed URL/proxy issue.

Common situations: Offline or flaky network during a long multi-turn session; corporate proxy blocking generativelanguage.googleapis.com; user cancellation propagating an abort; VPN drops mid-request.

Related errors


AI-assisted analysis of thedotmack/claude-mem@d8bc9755e7 (2026-09-17). Data as JSON: /api/errors/0e5b0ed0d34c6b0e. Report an issue: GitHub.

Appendix: source

Thrown at src/services/worker/GeminiProvider.ts:351

      turns: history.length,
      totalChars
    });

    const url = `${GEMINI_API_URL}/${model}:generateContent?key=${apiKey}`;

    await enforceRateLimitForModel(model, rateLimitingEnabled);

    // Track request-id (best-effort dedup) across retries.
    let priorRequestId: string | null = null;

    const data = await withRetry<GeminiResponse>(async (attemptSignal) => {
      let response: Response;
      try {
        response = await this.fetchGenerateContent(url, contents, priorRequestId, attemptSignal);
      } catch (networkError: unknown) {
        // Network failures, aborts, DNS, etc.
        const err = networkError instanceof Error ? networkError : new Error(String(networkError));
        throw classifyGeminiError({
          cause: err,
        });
      }

      const requestId = response.headers.get('x-goog-request-id') ?? response.headers.get('x-request-id');
      if (requestId) {
        priorRequestId = requestId;
      } else {
        logger.debug('SDK', 'Gemini response missing request-id header; retry dedup is best-effort');
      }

      if (!response.ok) {
        const errorBody = await response.text();
        throw classifyGeminiError({
          status: response.status,
          bodyText: errorBody,
          headers: response.headers,
          cause: new Error(`Gemini API error (status ${response.status})`),

View on GitHub (pinned to d8bc9755e7)