{"record":{"id":"d3f491dc35c638f1","repo":"BerriAI/litellm","slug":"google-pse-engine-id-is-not-set-set-google-pse-e","errorCode":null,"errorMessage":"GOOGLE_PSE_ENGINE_ID is not set. Set `GOOGLE_PSE_ENGINE_ID` environment variable or pass `search_engine_id` parameter.","messagePattern":"GOOGLE_PSE_ENGINE_ID is not set\\. Set `GOOGLE_PSE_ENGINE_ID` environment variable or pass `search_engine_id` parameter\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/llms/google_pse/search/transformation.py","lineNumber":97,"sourceCode":"        Validate environment and return headers.\n\n        Google PSE uses API key as a query parameter, not in headers.\n        This method is called but headers are not used for authentication.\n        \"\"\"\n        api_key = self.resolve_server_api_key(\n            caller_api_key=api_key,\n            caller_api_base=api_base,\n            key_env_vars=(\"GOOGLE_PSE_API_KEY\",),\n            base_env_var=\"GOOGLE_PSE_API_BASE\",\n            default_api_base=self.GOOGLE_PSE_API_BASE,\n        )\n        if not api_key:\n            raise ValueError(\"GOOGLE_PSE_API_KEY is not set. Set `GOOGLE_PSE_API_KEY` environment variable.\")\n\n        # Also check for search engine ID\n        search_engine_id: Final = kwargs.get(\"search_engine_id\") or get_secret_str(\"GOOGLE_PSE_ENGINE_ID\")\n        if not search_engine_id:\n            raise ValueError(\n                \"GOOGLE_PSE_ENGINE_ID is not set. Set `GOOGLE_PSE_ENGINE_ID` environment variable or pass `search_engine_id` parameter.\"\n            )\n\n        headers[\"Content-Type\"] = \"application/json\"\n        return headers\n\n    def get_complete_url(\n        self,\n        api_base: str | None,\n        optional_params: dict,\n        data: dict | list[dict] | None = None,\n        **kwargs,\n    ) -> str:\n        \"\"\"\n        Get complete URL for Search endpoint with query parameters.\n\n        Google PSE uses GET requests, so we build the full URL with query params here.\n        The transformed request body (data) contains the parameters needed for the URL.","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/llms/google_pse/search/transformation.py#L79-L115","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Create a Programmable Search Engine at programmablesearchengine.google.com, copy its ID (cx value), and export GOOGLE_PSE_ENGINE_ID=<id>.","Or pass search_engine_id per call if engines vary by request.","Ensure the engine is configured to search the whole web (or desired sites) and the API key's project has Custom Search API enabled.","Add both GOOGLE_PSE_API_KEY and GOOGLE_PSE_ENGINE_ID to your deployment secrets checklist."],"exampleFix":"# before\nos.environ[\"GOOGLE_PSE_API_KEY\"] = \"AIza...\"\n# GOOGLE_PSE_ENGINE_ID missing -> ValueError\nresults = litellm.web_search(provider=\"google_pse\", query=\"hello\")\n\n# after\nos.environ[\"GOOGLE_PSE_API_KEY\"] = \"AIza...\"\nos.environ[\"GOOGLE_PSE_ENGINE_ID\"] = \"a1b2c3d4e5f6g7h8j\"\nresults = litellm.web_search(provider=\"google_pse\", query=\"hello\")","handlingStrategy":"validation","validationCode":"import os\n\nengine_id = os.getenv(\"GOOGLE_PSE_ENGINE_ID\")\nif not engine_id:\n    raise RuntimeError(\n        \"GOOGLE_PSE_ENGINE_ID missing: create a Programmable Search Engine \"\n        \"(programmablesearchengine.google.com) and export its ID (cx) as GOOGLE_PSE_ENGINE_ID\"\n    )","typeGuard":"def google_pse_engine_id_ready() -> bool:\n    import os\n    return bool(os.getenv(\"GOOGLE_PSE_ENGINE_ID\") or os.getenv(\"GOOGLE_PSE_ENGINE_ID_SECRET\"))","tryCatchPattern":"try:\n    results = litellm.web_search(provider=\"google_pse\", query=q)\nexcept ValueError as e:\n    if \"GOOGLE_PSE_ENGINE_ID\" in str(e):\n        raise RuntimeError(\"Set GOOGLE_PSE_ENGINE_ID (the 'cx' from your Programmable Search Engine) or pass search_engine_id\") from e\n    raise","preventionTips":["The engine ID (cx) is separate from the API key — provision both.","Store GOOGLE_PSE_ENGINE_ID beside GOOGLE_PSE_API_KEY in the same secret set.","Support per-request search_engine_id when multiple engines are used.","Validate both vars in a config pre-flight shared by all search features."],"tags":["google-pse","search","configuration","engine-id","environment"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}