BerriAI/litellm · error · ValueError

OpenAI client is not an instance of AsyncOpenAI. Make sure y

Error message

OpenAI client is not an instance of AsyncOpenAI. Make sure you passed an AsyncOpenAI client.

What it means

When _is_async=True, AzureFineTuningAPI.create_fine_tuning_job verifies the resolved client is AsyncOpenAI/AsyncAzureOpenAI before delegating to acreate_fine_tuning_job. This error signals that a synchronous OpenAI/AzureOpenAI client reached the async dispatch. It is raised locally, before fine_tuning.jobs.create is invoked.

Source

Thrown at litellm/llms/azure/fine_tuning/handler.py:89

        openai_client: Final[OpenAI | AsyncOpenAI | AzureOpenAI | AsyncAzureOpenAI | None] = self.get_openai_client(
            api_key=api_key,
            api_base=api_base,
            timeout=timeout,
            max_retries=max_retries,
            organization=organization,
            client=client,
            _is_async=_is_async,
            api_version=api_version,
        )
        if openai_client is None:
            raise ValueError(
                "Azure OpenAI client is not initialized. Make sure api_key is passed or AZURE_API_KEY is set in the environment."
            )

        if _is_async is True:
            if not isinstance(openai_client, (AsyncOpenAI, AsyncAzureOpenAI)):
                raise ValueError(
                    "OpenAI client is not an instance of AsyncOpenAI. Make sure you passed an AsyncOpenAI client."
                )
            return self.acreate_fine_tuning_job(
                create_fine_tuning_job_data=create_fine_tuning_job_data,
                openai_client=openai_client,
            )

        verbose_logger.debug("creating fine tuning job, args= %s", create_fine_tuning_job_data)
        response: Final = cast(OpenAI, openai_client).fine_tuning.jobs.create(**create_fine_tuning_job_data)
        return _litellm_fine_tuning_job_from_response(response, is_azure=True)

    def cancel_fine_tuning_job(
        self,
        _is_async: bool,
        fine_tuning_job_id: str,
        api_key: str | None,
        api_base: str | None,
        api_version: str | None,

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Construct the client with AsyncOpenAI/AsyncAzureOpenAI for async submission.
  2. Keep the sync path (omit _is_async=True) if a sync client is all you need.
  3. Introduce a client factory keyed by is_async so mismatches cannot occur.

Example fix

# before
client = AzureOpenAI(api_key=k, azure_endpoint=b)
job = await azure_finetune.create_fine_tuning_job(data, client=client, _is_async=True)

# after
client = AsyncAzureOpenAI(api_key=k, azure_endpoint=b)
job = await azure_finetune.create_fine_tuning_job(data, client=client, _is_async=True)
Defensive patterns

Strategy: type-guard

Validate before calling

from openai import AsyncOpenAI, AsyncAzureOpenAI

assert isinstance(client, (AsyncOpenAI, AsyncAzureOpenAI)), 'async fine-tuning needs an async client'

Type guard

def is_async_ft_client(c: object) -> bool:
    from openai import AsyncOpenAI, AsyncAzureOpenAI
    return isinstance(c, (AsyncOpenAI, AsyncAzureOpenAI))

Try / catch

try:
    job = await ft.create_fine_tuning_job(data, client=client, _is_async=True)
except ValueError as e:
    if 'AsyncOpenAI' in str(e):
        raise TypeError('sync client in async fine-tuning create') from e
    raise

Prevention

When it happens

Trigger: Awaiting create_fine_tuning_job(data, client=OpenAI(...) or AzureOpenAI(...), _is_async=True); async training pipelines whose shared client was constructed with the sync class.

Common situations: Moving fine-tune submission scripts into async schedulers (Airflow async, Celery with asyncio) while reusing sync client objects; test fixtures that only build the sync class.

Related errors


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