{"record":{"id":"37679c5c6368be7a","repo":"BerriAI/litellm","slug":"azure-ad-token-must-be-a-string-got-type-token","errorCode":null,"errorMessage":"Azure AD token must be a string, got {type(token)}","messagePattern":"Azure AD token must be a string, got (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"litellm/llms/azure/common_utils.py","lineNumber":373,"sourceCode":"            )\n            raise e\n\n        #########################################################\n        # If litellm.enable_azure_ad_token_refresh is True and no other token provider is available,\n        # try to get DefaultAzureCredential provider\n        #########################################################\n        if azure_ad_token_provider is None and azure_ad_token is None:\n            azure_ad_token_provider = BaseAzureLLM._try_get_default_azure_credential_provider(\n                scope=scope,\n            )\n\n    # Execute the token provider to get the token if available\n    if azure_ad_token_provider and callable(azure_ad_token_provider):\n        try:\n            token: Final = azure_ad_token_provider()\n            if not isinstance(token, str):\n                verbose_logger.error(\"Azure AD token provider returned non-string value: %s\", type(token))\n                raise TypeError(f\"Azure AD token must be a string, got {type(token)}\")\n            else:\n                azure_ad_token = token\n        except TypeError:\n            # Re-raise TypeError directly\n            raise\n        except Exception as e:\n            verbose_logger.error(\"Error calling Azure AD token provider: %s\", e)\n            raise RuntimeError(f\"Failed to get Azure AD token: {e}\") from e\n\n    return azure_ad_token\n\n\nclass BaseAzureLLM(BaseOpenAILLM):\n    @staticmethod\n    def _try_get_default_azure_credential_provider(\n        scope: str,\n    ) -> Callable[[], str] | None:\n        \"\"\"","sourceCodeStart":355,"sourceCodeEnd":391,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/llms/azure/common_utils.py#L355-L391","documentation":"When a custom azure_ad_token_provider callable is used, LiteLLM invokes it and requires the return value to be a str. A non-string (None, bytes, dict, azure.core.credentials.AccessToken object) raises TypeError('Azure AD token must be a string, got {type}'). This guards the SDK before the value is placed in an Authorization header.","triggerScenarios":"Passing a provider like lambda: azure_identity.get_certificate_credential(...).get_token(scope) that returns an AccessToken object, not .token; returning None when the credential chain fails silently; returning bytes from a secret fetch.","commonSituations":"Wrapping azure-identity credentials: developers return credential.get_token(scope) instead of credential.get_token(scope).token; async providers (returning a coroutine) passed to the sync path; caching layers that store the whole token response dict.","solutions":["Make the provider return only the string: lambda: cred.get_token(scope).token.","If the provider is async, either await it inside a sync wrapper or use the async call path that supports it.","Add a None check inside your provider and raise a clear error there instead of returning None."],"exampleFix":"# before\ndef provider():\n    return DefaultAzureCredential().get_token(\"https://cognitiveservices.azure.com/.default\")  # AccessToken object\n\n# after\ndef provider():\n    return DefaultAzureCredential().get_token(\"https://cognitiveservices.azure.com/.default\").token  # str","handlingStrategy":"type-guard","validationCode":"def checked_provider(provider):\n    token = provider()\n    if not isinstance(token, str) or not token:\n        raise TypeError(f\"provider returned {type(token).__name__}, expected str\")\n    return token","typeGuard":"from typing import Callable, TypeGuard\n\ndef is_string_provider(p: Callable[[], object]) -> TypeGuard[Callable[[], str]]:\n    result = p()\n    return isinstance(result, str) and len(result) > 0","tryCatchPattern":"try:\n    resp = litellm.completion(..., azure_ad_token_provider=provider)\nexcept TypeError as e:\n    if \"must be a string\" in str(e):\n        # unwrap azure-identity AccessToken: provider returned AccessToken, need .token\n        raise RuntimeError(\"Fix provider to return credential.get_token(scope).token\") from e\n    raise","preventionTips":["Always return cred.get_token(scope).token from azure-identity wrappers.","Unit-test custom providers: assert isinstance(result, str).","Never return the full token response object or bytes from a provider."],"tags":["azure","authentication","type-error","token-provider"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}