Mintplex-Labs/anything-llm · warning · RetryError

Gemini error: ${this._lastErrorMessage}

Error message

Gemini error: ${this._lastErrorMessage}

What it means

GeminiProvider.stream() catch block (gemini.js:343-356) builds errorMsg from _lastErrorMessage captured by the custom fetch wrapper (gemini.js:22-40, which parses the non-2xx response body), prefixes it with "Gemini error: ", and throws RetryError for RateLimitError/InternalServerError/APIError. AuthenticationError is rethrown verbatim so credential failures do not retry. RetryError signals the AIbitat loop to re-attempt.

Source

Thrown at server/utils/agents/aibitat/providers/gemini.js:355

      return {
        textResponse: completion.content,
        functionCall: null,
        cost: this.getCost(),
        uuid: msgUUID,
      };
    } catch (error) {
      this.#logAPIError(error);
      const errorMsg = this._lastErrorMessage
        ? `Gemini error: ${this._lastErrorMessage}`
        : error.message;
      this._lastErrorMessage = null;
      if (error instanceof OpenAI.AuthenticationError) throw error;
      if (
        error instanceof OpenAI.RateLimitError ||
        error instanceof OpenAI.InternalServerError ||
        error instanceof OpenAI.APIError // Also will catch AuthenticationError!!!
      ) {
        throw new RetryError(errorMsg);
      }

      throw error;
    }
  }

  /**
   * Create a completion based on the received messages.
   *
   * @param messages A list of messages to send to the Gemini API.
   * @param functions
   * @returns The completion.
   */
  async complete(messages, functions = []) {
    if (!this.supportsToolCalling)
      throw new Error(`Gemini: ${this.model} does not support tool calling.`);
    this.providerLog("Gemini.complete - will process this chat completion.");
    this.resetUsage();

View on GitHub (pinned to 526360e320)

Solutions

  1. Read the full "Gemini error: ..." text and _lastErrorMessage to find the exact upstream cause.
  2. Reduce request rate or add backoff when the cause is 429/quota.
  3. Verify billing/quota status in the Google AI console.
  4. For multi-turn tool calls, ensure the thought_signature (extra_content) from the prior call is passed back in #formatMessages.
  5. Let the AIbitat retry loop handle transient 5xx cases.
Defensive patterns

Strategy: retry

Validate before calling

// Before streaming, sanity-check the API key and tool payload shape.
if (!process.env.GEMINI_API_KEY) throw new Error("GEMINI_API_KEY is not set.");
for (const f of functions) {
  if (!f.name || !/^[A-Za-z]/.test(f.name))
    throw new Error(`Tool name ${f.name} is invalid for Gemini.`);
}

Try / catch

const { RetryError } = require("./server/utils/agents/aibitat/error.js");
try {
  return await provider.stream(messages, functions, handler);
} catch (e) {
  if (e instanceof RetryError && /quota|rate/i.test(e.message)) {
    await new Promise((r) => setTimeout(r, 2000));
    return await provider.stream(messages, functions, handler);
  }
  throw e;
}

Prevention

When it happens

Trigger: Gemini returns 429 (quota/rate limit), 500/503, or a 400 APIError such as a missing thought_signature (extra_content) on a multi-turn tool result. The fetch wrapper captured the body message, which is what surfaces here.

Common situations: Free-tier quota exhaustion, high request rate, sending tool results back without the Gemini-required thought_signature, or a malformed tool payload that Gemini rejects with APIError.

Related errors


AI-assisted analysis of Mintplex-Labs/anything-llm@526360e320 (2026-08-13). Data as JSON: /api/errors/8cf39d491d159b64. Report an issue: GitHub.