BerriAI/litellm · error · AzureOpenAIError

max retries must be an int

Error message

max retries must be an int

What it means

Before constructing the sync Azure OpenAI client, LiteLLM pops `max_retries` from optional_params and requires it to be an int (None falls back to the default, so unset is fine). Any other type — string, float, bool-like objects — raises this 422. This protects the underlying OpenAI SDK, which type-checks the value.

Source

Thrown at litellm/llms/azure/azure.py:329

                    litellm_params=litellm_params,
                )
            else:
                ## LOGGING
                logging_obj.pre_call(
                    input=messages,
                    api_key=api_key,
                    additional_args={
                        "headers": {
                            "api_key": api_key,
                            "azure_ad_token": azure_ad_token,
                        },
                        "api_version": api_version,
                        "api_base": api_base,
                        "complete_input_dict": data,
                    },
                )
                if not isinstance(max_retries, int):
                    raise AzureOpenAIError(status_code=422, message="max retries must be an int")
                # init AzureOpenAI Client
                azure_client: Final = self.get_azure_openai_client(
                    api_version=api_version,
                    api_base=api_base,
                    api_key=api_key,
                    model=model,
                    client=client,
                    _is_async=False,
                    litellm_params=litellm_params,
                )
                if not isinstance(azure_client, (AzureOpenAI, OpenAI)):
                    raise AzureOpenAIError(
                        status_code=500,
                        message="azure_client is not an instance of AzureOpenAI or OpenAI",
                    )

                headers, response = self.make_sync_azure_openai_chat_completion_request(
                    azure_client=azure_client, data=data, timeout=timeout

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Pass max_retries as an int: max_retries=3.
  2. Coerce config values at load time: int(os.environ.get('MAX_RETRIES', 2)).
  3. Or omit max_retries entirely to use LiteLLM's default.

Example fix

# before
litellm.completion(model=..., messages=msgs, max_retries=os.environ['MAX_RETRIES'])

# after
litellm.completion(model=..., messages=msgs, max_retries=int(os.environ.get('MAX_RETRIES', 2)))
Defensive patterns

Strategy: type-guard

Validate before calling

raw = config.get('max_retries')
max_retries = int(raw) if raw is not None else None  # None -> litellm default

Type guard

def is_valid_max_retries(v) -> bool:
    return v is None or (isinstance(v, int) and not isinstance(v, bool))

Prevention

When it happens

Trigger: Passing max_retries='3' (string from env/config), max_retries=3.0 (float), or max_retries=[3] to litellm.completion with an azure model.

Common situations: Reading retry counts from environment variables or YAML config which arrive as strings; JSON configs where the value was quoted.

Related errors


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