{"record":{"id":"4221284972995067","repo":"BerriAI/litellm","slug":"get-complete-url-must-be-implemented-by-provider-422128","errorCode":null,"errorMessage":"get_complete_url must be implemented by provider","messagePattern":"get_complete_url must be implemented by provider","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"litellm/llms/base_llm/search/transformation.py","lineNumber":211,"sourceCode":"        \"\"\"\n        Get complete URL for Search endpoint.\n\n        Args:\n            api_base: Base URL for the API\n            optional_params: Optional parameters for the request\n            data: Transformed request body from transform_search_request().\n                  Some providers (e.g., Google PSE) use GET requests and need\n                  the request body to construct query parameters in the URL.\n                  Can be a dict or list of dicts depending on provider.\n            **kwargs: Additional keyword arguments\n\n        Returns:\n            Complete URL for the search endpoint\n\n        Note:\n            Override in provider-specific implementations.\n        \"\"\"\n        raise NotImplementedError(\"get_complete_url must be implemented by provider\")\n\n    def transform_search_request(\n        self,\n        query: str | list[str],\n        optional_params: dict,\n        **kwargs,\n    ) -> dict | list[dict]:\n        \"\"\"\n        Transform Search request to provider-specific format.\n        Override in provider-specific implementations.\n\n        Args:\n            query: Search query (string or list of strings)\n            optional_params: Optional parameters for the request\n\n        Returns:\n            Dict with request data\n        \"\"\"","sourceCodeStart":193,"sourceCodeEnd":229,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/llms/base_llm/search/transformation.py#L193-L229","documentation":"BaseSearchConfig.get_complete_url() is an abstract hook that must build the full search endpoint URL (some providers like Google PSE encode the query into GET query params using the transformed body). The base class raises NotImplementedError. Hitting it means a search request was routed to a config that never implemented URL construction — the base class or an incomplete custom provider.","triggerScenarios":"Invoking litellm search (provider web-search path) with a provider whose config class does not override get_complete_url — e.g. registering a custom search provider that only partially implements the interface, or a version mismatch where a new provider was expected to supply it.","commonSituations":"Adding a custom search backend (internal enterprise search) and missing the URL builder; copying an example config that predates the interface; provider handler registered under the wrong class.","solutions":["Use a built-in search provider config that implements get_complete_url (e.g. the Google PSE / Exa / Tavily configs in litellm/llms/*/search/transformation.py) as your template.","In your custom config, implement `def get_complete_url(self, api_base, api_key, query, data, **kwargs) -> str` returning the full endpoint URL.","Verify the provider name you pass resolves to your concrete class, not BaseSearchConfig."],"exampleFix":"# before\nclass MySearch(BaseSearchConfig):\n    pass  # -> NotImplementedError('get_complete_url must be implemented by provider')\n\n# after\nclass MySearch(BaseSearchConfig):\n    def get_complete_url(self, api_base, api_key, query, data, **kwargs) -> str:\n        return f\"{api_base or 'https://api.mysearch.io'}/v1/search\"","handlingStrategy":"type-guard","validationCode":"from litellm.llms.base_llm.search.transformation import BaseSearchConfig\n\nassert type(cfg).get_complete_url is not BaseSearchConfig.get_complete_url, \"get_complete_url not implemented\"","typeGuard":"from litellm.llms.base_llm.search.transformation import BaseSearchConfig\n\ndef search_config_is_complete(cfg: BaseSearchConfig) -> bool:\n    return all(\n        getattr(type(cfg), m) is not getattr(BaseSearchConfig, m)\n        for m in (\"get_complete_url\", \"transform_search_request\", \"transform_search_response\")\n    )","tryCatchPattern":null,"preventionTips":["Model custom search providers on an existing built-in config so all three hooks get implemented.","Add interface-conformance tests for every custom provider config in CI."],"tags":["search-api","not-implemented","abstract-method","litellm"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}