BerriAI/litellm · error · ValueError

GOOGLE_PSE_ENGINE_ID is not set. Set `GOOGLE_PSE_ENGINE_ID`

Error message

GOOGLE_PSE_ENGINE_ID is not set. Set `GOOGLE_PSE_ENGINE_ID` environment variable or pass `search_engine_id` parameter.

What it means

Raised by the Google PSE provider during header setup when the search engine ID is missing: neither a search_engine_id kwarg nor the GOOGLE_PSE_ENGINE_ID environment variable/secret is present. The engine ID (the 'cx' parameter) identifies which Programmable Search Engine to query; without it Google returns 400 even with a valid API key. litellm checks the key first, so this error implies the API key was resolved successfully.

Source

Thrown at litellm/llms/google_pse/search/transformation.py:97

        Validate environment and return headers.

        Google PSE uses API key as a query parameter, not in headers.
        This method is called but headers are not used for authentication.
        """
        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,
        )
        if not api_key:
            raise ValueError("GOOGLE_PSE_API_KEY is not set. Set `GOOGLE_PSE_API_KEY` environment variable.")

        # Also check for search engine ID
        search_engine_id: Final = kwargs.get("search_engine_id") or get_secret_str("GOOGLE_PSE_ENGINE_ID")
        if not search_engine_id:
            raise ValueError(
                "GOOGLE_PSE_ENGINE_ID is not set. Set `GOOGLE_PSE_ENGINE_ID` environment variable or pass `search_engine_id` parameter."
            )

        headers["Content-Type"] = "application/json"
        return headers

    def get_complete_url(
        self,
        api_base: str | None,
        optional_params: dict,
        data: dict | list[dict] | None = None,
        **kwargs,
    ) -> str:
        """
        Get complete URL for Search endpoint with query parameters.

        Google PSE uses GET requests, so we build the full URL with query params here.
        The transformed request body (data) contains the parameters needed for the URL.

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Create a Programmable Search Engine at programmablesearchengine.google.com, copy its ID (cx value), and export GOOGLE_PSE_ENGINE_ID=<id>.
  2. Or pass search_engine_id per call if engines vary by request.
  3. Ensure the engine is configured to search the whole web (or desired sites) and the API key's project has Custom Search API enabled.
  4. Add both GOOGLE_PSE_API_KEY and GOOGLE_PSE_ENGINE_ID to your deployment secrets checklist.

Example fix

# before
os.environ["GOOGLE_PSE_API_KEY"] = "AIza..."
# GOOGLE_PSE_ENGINE_ID missing -> ValueError
results = litellm.web_search(provider="google_pse", query="hello")

# after
os.environ["GOOGLE_PSE_API_KEY"] = "AIza..."
os.environ["GOOGLE_PSE_ENGINE_ID"] = "a1b2c3d4e5f6g7h8j"
results = litellm.web_search(provider="google_pse", query="hello")
Defensive patterns

Strategy: validation

Validate before calling

import os

engine_id = os.getenv("GOOGLE_PSE_ENGINE_ID")
if not engine_id:
    raise RuntimeError(
        "GOOGLE_PSE_ENGINE_ID missing: create a Programmable Search Engine "
        "(programmablesearchengine.google.com) and export its ID (cx) as GOOGLE_PSE_ENGINE_ID"
    )

Type guard

def google_pse_engine_id_ready() -> bool:
    import os
    return bool(os.getenv("GOOGLE_PSE_ENGINE_ID") or os.getenv("GOOGLE_PSE_ENGINE_ID_SECRET"))

Try / catch

try:
    results = litellm.web_search(provider="google_pse", query=q)
except ValueError as e:
    if "GOOGLE_PSE_ENGINE_ID" in str(e):
        raise RuntimeError("Set GOOGLE_PSE_ENGINE_ID (the 'cx' from your Programmable Search Engine) or pass search_engine_id") from e
    raise

Prevention

When it happens

Trigger: Calling google_pse search with GOOGLE_PSE_API_KEY set but GOOGLE_PSE_ENGINE_ID unset, and no search_engine_id passed per-request. Common right after fixing the API key error (1636): users provision the key but forget the engine ID is a separate value from the Programmable Search Engine control panel.

Common situations: Partial configuration copied from docs that only mention the API key; using a Google Cloud project key and assuming the engine ID is derivable; new environments seeded with only the API key secret.

Related errors


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