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
- Read the full "Gemini error: ..." text and _lastErrorMessage to find the exact upstream cause.
- Reduce request rate or add backoff when the cause is 429/quota.
- Verify billing/quota status in the Google AI console.
- For multi-turn tool calls, ensure the thought_signature (extra_content) from the prior call is passed back in #formatMessages.
- 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
- Pass the Gemini thought_signature (extra_content) back on every tool result.
- Keep tool names alphabetic-leading (the gtc__ prefix handles this).
- Watch quota in the Google AI console to avoid surprise 429s.
- Log _lastErrorMessage so the real upstream cause is recoverable.
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.