BerriAI/litellm · error · ValueError
GOOGLE_PSE_ENGINE_ID is required
Error message
GOOGLE_PSE_ENGINE_ID is required
What it means
Raised in the google_pse search-execution path when search_engine_id is still falsy after checking the per-request parameter and the GOOGLE_PSE_ENGINE_ID secret. Same missing-cx failure as error 1637, raised at request-build time with the shorter 'is required' message. It fires only after the API key check passes, so seeing it means key resolution succeeded.
Source
Thrown at litellm/llms/google_pse/search/transformation.py:178
# Google PSE only supports single string queries
query = " ".join(query)
# Get API credentials. The key is sent as a query param to api_base, so
# resolve it host-aware to avoid leaking a server-managed key to a
# caller-supplied host.
api_key = self.resolve_server_api_key(
caller_api_key=api_key,
caller_api_base=api_base,
key_env_vars=("GOOGLE_PSE_API_KEY",),
base_env_var="GOOGLE_PSE_API_BASE",
default_api_base=self.GOOGLE_PSE_API_BASE,
)
search_engine_id = search_engine_id or get_secret_str("GOOGLE_PSE_ENGINE_ID")
if not api_key:
raise ValueError("GOOGLE_PSE_API_KEY is required")
if not search_engine_id:
raise ValueError("GOOGLE_PSE_ENGINE_ID is required")
request_data: Final[GooglePSESearchRequest] = {
"q": query,
"cx": search_engine_id,
"key": api_key,
}
# Transform unified spec parameters to Google PSE format
if "max_results" in optional_params:
# Google PSE supports 1-10 results per request
num_results: Final = min(optional_params["max_results"], 10)
request_data["num"] = num_results
if "search_domain_filter" in optional_params:
# Convert list to single domain (take first if multiple)
domains: Final = optional_params["search_domain_filter"]
if isinstance(domains, list) and len(domains) > 0:
request_data["siteSearch"] = domains[0]View on GitHub (pinned to 6c2dcb801b)
Solutions
- Set GOOGLE_PSE_ENGINE_ID to the Programmable Search Engine ID (cx) in the runtime environment.
- Or pass search_engine_id explicitly on each search call.
- Add a startup assertion that both GOOGLE_PSE_API_KEY and GOOGLE_PSE_ENGINE_ID are non-empty before serving search requests.
- Verify the value actually reaches litellm (get_secret_str reads env and secret managers — check both sources).
Example fix
# before: kwarg dropped in a refactor -> engine id resolves to None
engine = config.get("engine") # key is actually 'search_engine_id'
litellm.web_search(provider="google_pse", query="x")
# after: correct kwarg + env fallback asserted at boot
assert os.environ.get("GOOGLE_PSE_ENGINE_ID"), "GOOGLE_PSE_ENGINE_ID required"
litellm.web_search(provider="google_pse", query="x", search_engine_id=engine_id) Defensive patterns
Strategy: validation
Validate before calling
import os
def require_pse_engine_id(search_engine_id: str | None) -> str:
engine = search_engine_id or os.getenv("GOOGLE_PSE_ENGINE_ID")
if not engine:
raise ValueError("search_engine_id or GOOGLE_PSE_ENGINE_ID is required for google_pse")
return engine
engine_id = require_pse_engine_id(config.get("search_engine_id")) Type guard
def has_pse_engine_id(request_engine_id: str | None) -> bool:
"""Narrow a request to a usable google_pse engine ID."""
import os
return bool(request_engine_id or os.getenv("GOOGLE_PSE_ENGINE_ID")) Try / catch
try:
results = litellm.web_search(provider="google_pse", query=q, search_engine_id=engine_id)
except ValueError as e:
if "GOOGLE_PSE_ENGINE_ID is required" in str(e):
engine_id = os.environ["GOOGLE_PSE_ENGINE_ID"] # load from trusted config, then retry once
results = litellm.web_search(provider="google_pse", query=q, search_engine_id=engine_id)
else:
raise Prevention
- Centralize engine-ID resolution (env fallback + kwarg) in one helper used by all call sites.
- Assert GOOGLE_PSE_ENGINE_ID at startup alongside the API key.
- Watch for kwarg renames in refactors (search_engine_id is the litellm name).
- For multi-engine setups, validate each tenant's engine ID before request time.
When it happens
Trigger: Building a google_pse search request with GOOGLE_PSE_API_KEY present but neither a search_engine_id argument nor GOOGLE_PSE_ENGINE_ID in the environment/secrets; e.g. per-request code that conditionally passes the engine ID and takes the wrong branch.
Common situations: Refactors that rename the kwarg (search_engine_id vs engine_id) so None is passed; multi-tenant setups where engine IDs live in a database but a null tenant slips through; deployments that fixed the key error and stopped before adding the engine secret.
Related errors
- GOOGLE_PSE_ENGINE_ID is not set. Set `GOOGLE_PSE_ENGINE_ID`
- GOOGLE_PSE_API_KEY is not set. Set `GOOGLE_PSE_API_KEY` envi
- GOOGLE_PSE_API_KEY is required
- Qdrant url must be provided
- Missing required Redis configuration: {missing_var}. Provide
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/ba5dfa9e38f11f44.
Report an issue: GitHub.