{"record":{"id":"a6af2e002e9472c3","repo":"microsoft/autogen","slug":"azure-ad-token-provider-must-be-a-azuretokenprovid","errorCode":null,"errorMessage":"azure_ad_token_provider must be a AzureTokenProvider to be component serialized","messagePattern":"azure_ad_token_provider must be a AzureTokenProvider to be component serialized","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/packages/autogen-ext/src/autogen_ext/models/openai/_openai_client.py","lineNumber":1727,"sourceCode":"            include_name_in_message=include_name_in_message,\n        )\n\n    def __getstate__(self) -> Dict[str, Any]:\n        state = self.__dict__.copy()\n        state[\"_client\"] = None\n        return state\n\n    def __setstate__(self, state: Dict[str, Any]) -> None:\n        self.__dict__.update(state)\n        self._client = _azure_openai_client_from_config(state[\"_raw_config\"])\n\n    def _to_config(self) -> AzureOpenAIClientConfigurationConfigModel:\n        from ...auth.azure import AzureTokenProvider\n\n        copied_config = self._raw_config.copy()\n        if \"azure_ad_token_provider\" in copied_config:\n            if not isinstance(copied_config[\"azure_ad_token_provider\"], AzureTokenProvider):\n                raise ValueError(\"azure_ad_token_provider must be a AzureTokenProvider to be component serialized\")\n\n            copied_config[\"azure_ad_token_provider\"] = (\n                copied_config[\"azure_ad_token_provider\"].dump_component().model_dump(exclude_none=True)\n            )\n\n        return AzureOpenAIClientConfigurationConfigModel(**copied_config)\n\n    @classmethod\n    def _from_config(cls, config: AzureOpenAIClientConfigurationConfigModel) -> Self:\n        from ...auth.azure import AzureTokenProvider\n\n        copied_config = config.model_copy().model_dump(exclude_none=True)\n\n        # Handle api_key as SecretStr\n        if \"api_key\" in copied_config and isinstance(config.api_key, SecretStr):\n            copied_config[\"api_key\"] = config.api_key.get_secret_value()\n\n        if \"azure_ad_token_provider\" in copied_config:","sourceCodeStart":1709,"sourceCodeEnd":1745,"githubUrl":"https://github.com/microsoft/autogen/blob/027ecf0a379bcc1d09956d46d12d44a3ad9cee14/python/packages/autogen-ext/src/autogen_ext/models/openai/_openai_client.py#L1709-L1745","documentation":"Thrown by AzureOpenAIChatCompletionClient._to_config during component serialization when azure_ad_token_provider is present in the raw config but is not an instance of autogen_ext.auth.azure.AzureTokenProvider. Serialization can only dump providers that implement the component API (dump_component), so arbitrary callables are rejected.","triggerScenarios":"Constructing the Azure client with azure_ad_token_provider=some_callable (any function, e.g. an async token getter passed directly) and then calling dump_component() / dump_component_json() on the client. Plain callables work at runtime but cannot be serialized.","commonSituations":"Following older examples that pass a raw DefaultAzureCredential token lambda; wrapping the client for checkpoint/persistence which triggers component serialization; copying auth code written before the AzureTokenProvider protocol existed.","solutions":["Wrap the callable in autogen_ext.auth.azure.AzureTokenProvider (implement/get or use the provided adapter) so it is serializable","If serialization is not needed, keep the callable but avoid dump_component on this client","Pass the token provider via a serializable custom AzureTokenProvider subclass whose config can round-trip"],"exampleFix":"# before\nfrom azure.identity import DefaultAzureCredential, get_bearer_token_provider\nclient = AzureOpenAIChatCompletionClient(\n    ..., azure_ad_token_provider=get_bearer_token_provider(DefaultAzureCredential(), \"https://cognitiveservices.azure.com/.default\")\n)\nclient.dump_component()  # ValueError\n\n# after\nfrom autogen_ext.auth.azure import AzureTokenProvider\nclass MyTokenProvider(AzureTokenProvider):\n    async def get_token(self):\n        return get_bearer_token_provider(DefaultAzureCredential(), \"https://cognitiveservices.azure.com/.default\")()\nclient = AzureOpenAIChatCompletionClient(..., azure_ad_token_provider=MyTokenProvider())\nclient.dump_component()  # ok","handlingStrategy":"type-guard","validationCode":"from autogen_ext.auth.azure import AzureTokenProvider\n\nprovider = config.get(\"azure_ad_token_provider\")\nif provider is not None and not isinstance(provider, AzureTokenProvider):\n    raise TypeError(\"wrap the callable in an AzureTokenProvider before constructing the client\")","typeGuard":"def is_serializable_token_provider(provider) -> bool:\n    from autogen_ext.auth.azure import AzureTokenProvider\n    return provider is None or isinstance(provider, AzureTokenProvider)","tryCatchPattern":"try:\n    component = client.dump_component()\nexcept ValueError as e:\n    if \"azure_ad_token_provider\" in str(e):\n        # reconstruct with a serializable provider before persisting\n        raise PersistenceError(\"re-wrap azure_ad_token_provider in AzureTokenProvider\") from e\n    raise","preventionTips":["Always wrap raw credential callables in an AzureTokenProvider subclass at construction time","Unit-test dump_component/load_component round-trips for every client you persist","Keep auth wiring in one module so all clients use the same provider pattern"],"tags":["azure","authentication","serialization","component-config"],"backgroundTag":null,"analyzedSha":"027ecf0a379bcc1d09956d46d12d44a3ad9cee14","analyzedAt":"2026-08-15T03:38:00.719Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}