BerriAI/litellm · error · GeminiError

{raw_response.text}

Error message

{raw_response.text}

What it means

_raise_for_status() in the Gemini agents transformation converts any non-2xx HTTP response into a GeminiError whose message is the raw response body text, carrying the status code and headers. The '{raw_response.text}' message is therefore Google's (or a proxy's) error payload — 400 invalid argument, 401/403 bad key, 404 unknown agent/model, 429 quota — surfaced verbatim.

Source

Thrown at litellm/llms/gemini/agents/transformation.py:122

        # an authenticated proxy user could set ``api_base`` to an attacker-
        # controlled host and have the proxy ship its shared Gemini key in the
        # ``x-goog-api-key`` header.
        if litellm_params.get("api_base") and not explicit_api_key:
            raise ValueError(
                "When overriding api_base for Gemini agents, you must also "
                "supply an explicit api_key. Falling back to GOOGLE_API_KEY / "
                "GEMINI_API_KEY env vars with a custom api_base is refused "
                "to prevent leaking the shared provider key to arbitrary hosts."
            )
        api_key: Final = GeminiModelInfo.get_api_key(explicit_api_key)
        if not api_key:
            raise ValueError("Google API key is required. Set GOOGLE_API_KEY or GEMINI_API_KEY, or pass api_key.")
        headers["x-goog-api-key"] = api_key
        return headers

    def _raise_for_status(self, raw_response: httpx.Response) -> None:
        if not (200 <= raw_response.status_code < 300):
            raise GeminiError(
                message=raw_response.text,
                status_code=raw_response.status_code,
                headers=dict(raw_response.headers),
            )

    # ------------------------------------------------------------------ #
    # CREATE                                                               #
    # ------------------------------------------------------------------ #

    def transform_create_request(
        self,
        name: str,
        litellm_params: dict[str, Any],
    ) -> dict[str, Any]:
        body: Final[dict[str, Any]] = {"name": name}
        for key in _GEMINI_AGENT_BODY_KEYS:
            value = litellm_params.get(key)
            if value is not None:

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Read the embedded body text — Google errors are JSON with '@type' and 'message' fields that state the exact problem.
  2. Map the carried status_code: 401/403 fix the key, 404 fix model/agent id, 400 fix the payload per the message, 429 back off or raise limits.
  3. For 429/5xx, retry with exponential backoff; GeminiError exposes status_code so branching is straightforward.

Example fix

# before
resp = litellm.agent_create(...)

# after
from litellm.llms.gemini.common_utils import GeminiError
try:
    resp = litellm.agent_create(...)
except GeminiError as e:
    if e.status_code == 429:
        time.sleep(30)
        resp = litellm.agent_create(...)
    else:
        raise
Defensive patterns

Strategy: try-catch

Try / catch

from litellm.llms.gemini.common_utils import GeminiError

try:
    resp = litellm.agent_create(...)
except GeminiError as e:
    body = e.message  # raw provider text; parse JSON if present
    if e.status_code == 429:
        backoff_and_retry()
    elif e.status_code in (401, 403):
        raise RuntimeError("Gemini auth failed; check API key") from e
    else:
        raise

Prevention

When it happens

Trigger: Any Gemini agents API call (agent create, list, run) that returns a non-2xx: malformed request body, invalid model name for the agent, expired API key, or exceeded quota.

Common situations: Agent config references a model the key has no access to; quota exhausted on the free AI Studio tier mid-run; malformed tool declarations produce a 400 with a details payload that lands in the message string.

Related errors


AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15). Data as JSON: /api/errors/4ed5f99177c6e98a. Report an issue: GitHub.