BerriAI/litellm · error · ValueError
When overriding api_base for Gemini agents, you must also su
Error message
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.
What it means
A deliberate security guard in the Gemini agents transformation: when the caller overrides api_base (e.g. routing through a custom host or proxy), litellm refuses to attach the process-wide GOOGLE_API_KEY/GEMINI_API_KEY and instead raises this ValueError demanding an explicit api_key. Without the guard, an attacker who can set api_base could point the request at their own host and exfiltrate the shared Gemini key via the x-goog-api-key header.
Source
Thrown at litellm/llms/gemini/agents/transformation.py:108
litellm_params: dict[str, Any],
) -> str:
return f"{self._base_url(api_base)}/agents"
def validate_environment(
self,
headers: dict[str, str],
litellm_params: dict[str, Any],
) -> dict[str, str]:
headers = dict(headers)
headers["Content-Type"] = "application/json"
explicit_api_key: Final = litellm_params.get("api_key")
# SECURITY: when the caller overrides ``api_base``, refuse to fall back
# to the process-wide GOOGLE_API_KEY / GEMINI_API_KEY env vars. Otherwise
# 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),
)View on GitHub (pinned to 6c2dcb801b)
Solutions
- Pass an explicit api_key together with the custom api_base: api_key='...' alongside api_base='...'.
- If the proxy injects its own upstream credentials, pass a placeholder/dedicated key scoped to that hop.
- Remove the api_base override to use the official Google endpoint, where the env-var fallback is allowed.
Example fix
# before litellm.completion(model="gemini/gemini-2.0-flash", messages=m, api_base="https://llm-gw.internal") # ValueError # after litellm.completion(model="gemini/gemini-2.0-flash", messages=m, api_base="https://llm-gw.internal", api_key=os.environ["GEMINI_GATEWAY_KEY"])
Defensive patterns
Strategy: validation
Validate before calling
def gemini_call_params(api_base: str | None, api_key: str | None) -> dict:
if api_base and not api_key:
raise ValueError(
"Custom api_base for Gemini agents requires an explicit api_key "
"(env-var fallback is disabled for security)"
)
return {k: v for k, v in {"api_base": api_base, "api_key": api_key}.items() if v} Type guard
def is_safe_gemini_base_override(litellm_params: dict) -> bool:
return not litellm_params.get("api_base") or bool(litellm_params.get("api_key")) Try / catch
try:
litellm.completion(model="gemini/gemini-2.0-flash", messages=m, api_base=gw_url)
except ValueError as e:
if "must also supply an explicit api_key" in str(e):
params["api_key"] = gateway_key # dedicated key for the overridden hop
litellm.completion(model="gemini/gemini-2.0-flash", messages=m, **params)
else:
raise Prevention
- Treat api_base overrides as privileged configuration: always pair them with an explicit key in the same config object.
- Give gateway/proxy hops their own dedicated key rather than reusing the production Gemini key.
- Wrap agent-call construction in one factory that enforces the api_base-implies-api_key invariant.
When it happens
Trigger: litellm_params contains api_base (custom proxy/gateway URL) but no api_key, e.g. completion(model='gemini/...', ..., api_base='https://my-proxy.example.com') while relying on env-var GEMINI_API_KEY.
Common situations: Routing Gemini agent traffic through an internal LLM gateway for logging/rate limiting; corporate proxy setups; testing against a local mock server. All previously worked by silently sending the env key to the overridden host, and now fail closed by design.
Related errors
- Google API key is required. Set GOOGLE_API_KEY or GEMINI_API
- api_base is required for Azure AI Agents. Set it via AZURE_A
- Refusing to send the server-configured {credential_name} to
- {raw_response.text}
- GEMINI_API_BASE or GEMINI_API_KEY/GOOGLE_API_KEY is not set.
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/3bd86563583e1d24.
Report an issue: GitHub.