BerriAI/litellm · error · AzureOpenAIError

azure_client is not an instance of AsyncAzureOpenAI

Error message

azure_client is not an instance of AsyncAzureOpenAI

What it means

The async text-completion path (acompletion) requires the client returned by get_azure_openai_client(..., _is_async=True) to be an AsyncAzureOpenAI instance; otherwise it raises AzureOpenAIError 500 before logging pre-call data. It is the async mirror of 1030 and catches sync clients, plain OpenAI clients, or mocks being injected into the async path.

Source

Thrown at litellm/llms/azure/completion/handler.py:216

        azure_ad_token: str | None = None,
        client=None,  # this is the AsyncAzureOpenAI
        litellm_params: dict = {},
    ):
        response = None
        try:
            # init AzureOpenAI Client
            # setting Azure client
            azure_client: Final = self.get_azure_openai_client(
                api_version=api_version,
                api_base=api_base,
                api_key=api_key,
                model=model,
                _is_async=True,
                client=client,
                litellm_params=litellm_params,
            )
            if not isinstance(azure_client, AsyncAzureOpenAI):
                raise AzureOpenAIError(
                    status_code=500,
                    message="azure_client is not an instance of AsyncAzureOpenAI",
                )

            ## LOGGING
            logging_obj.pre_call(
                input=data["prompt"],
                api_key=azure_client.api_key,
                additional_args={
                    "headers": {"Authorization": f"Bearer {azure_client.api_key}"},
                    "api_base": azure_client._base_url._uri_reference,
                    "acompletion": True,
                    "complete_input_dict": data,
                },
            )
            raw_response: Final = await azure_client.completions.with_raw_response.create(**data, timeout=timeout)
            response = raw_response.parse()
            return openai_text_completion_config.convert_to_chat_model_response_object(

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Remove the client= argument and let LiteLLM build the async client, or pass AsyncAzureOpenAI(...) explicitly.
  2. Keep separate clients per mode: azure_client (sync) and azure_async_client (async).
  3. When mocking, patch with AsyncAzureOpenAI instances or MagicMock(spec=AsyncAzureOpenAI).

Example fix

# before
client = AzureOpenAI(...)  # sync
resp = await llm.acompletion(..., client=client)

# after
client = AsyncAzureOpenAI(api_key=..., azure_endpoint=..., api_version=...)
resp = await llm.acompletion(..., client=client)
Defensive patterns

Strategy: type-guard

Validate before calling

from openai import AsyncAzureOpenAI

def validate_async_client(client) -> None:
    if client is not None and not isinstance(client, AsyncAzureOpenAI):
        raise ConfigError(f"async path needs AsyncAzureOpenAI, got {type(client).__name__}")

Type guard

from openai import AsyncAzureOpenAI
from typing import TypeGuard

def is_async_azure_client(c: object) -> TypeGuard[AsyncAzureOpenAI]:
    return isinstance(c, AsyncAzureOpenAI)

Try / catch

try:
    resp = await llm.acompletion(...)
except AzureOpenAIError as e:
    if "not an instance of AsyncAzureOpenAI" in str(e):
        raise ConfigError("Pass AsyncAzureOpenAI or omit client=") from e
    raise

Prevention

When it happens

Trigger: Passing a sync AzureOpenAI or OpenAI instance as client= to an await-ed azure text completion; a client factory configured without _is_async; stale clients reused after switching call styles.

Common situations: Codebases with both sync and async entry points sharing one client variable; FastAPI handlers refactoring from sync to async while keeping the module-level client; test fixtures mocking only the sync class.

Related errors


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