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 AzureOpenAI SDK client for text completion, LiteLLM pops max_retries from optional_params (default 2) and requires it to be an int; anything else raises AzureOpenAIError 422. The OpenAI SDK's max_retries parameter is passed straight through, so a non-int would fail deeper with a worse message.
Source
Thrown at litellm/llms/azure/completion/handler.py:141
client=client,
)
else:
## LOGGING
logging_obj.pre_call(
input=prompt,
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_key=api_key,
api_base=api_base,
api_version=api_version,
client=client,
litellm_params=litellm_params,
_is_async=False,
model=model,
)
if not isinstance(azure_client, AzureOpenAI):
raise AzureOpenAIError(
status_code=500,
message="azure_client is not an instance of AzureOpenAI",
)
raw_response: Final = azure_client.completions.with_raw_response.create(**data, timeout=timeout)View on GitHub (pinned to 6c2dcb801b)
Solutions
- Pass an int: litellm.text_completion(..., max_retries=3).
- Coerce config-sourced values: max_retries=int(cfg["max_retries"]) with a safe default.
- In proxy configs, put the literal integer in YAML rather than an env-string substitution.
Example fix
# before
max_retries = os.environ.get("MAX_RETRIES", "2") # str!
# after
max_retries = int(os.environ.get("MAX_RETRIES", "2")) Defensive patterns
Strategy: type-guard
Validate before calling
max_retries = cfg.get("max_retries", 2)
assert isinstance(max_retries, int) and not isinstance(max_retries, bool), "max_retries must be int" Type guard
def is_int_retries(v: object) -> bool:
return isinstance(v, int) and not isinstance(v, bool) Try / catch
try:
resp = litellm.text_completion(..., max_retries=cfg["max_retries"])
except AzureOpenAIError as e:
if e.status_code == 422 and "max retries" in str(e):
resp = litellm.text_completion(..., max_retries=int(cfg["max_retries"]))
else:
raise Prevention
- Coerce config-sourced numbers once at load: int()/float() with defaults.
- Keep retry counts as literal ints in YAML, not env-string substitutions.
- Add JSON-schema validation (type: integer) for config files.
When it happens
Trigger: Passing max_retries="5" (string from an env var or config file), max_retries=5.0, or None through optional_params to the azure text-completion path.
Common situations: Proxy YAML configs where numeric-looking values come from os.environ/<VAR> substitutions that yield strings; JSON configs with float values; templating systems that stringify numbers.
Related errors
- Expected document dict, got {type(document)}
- limit must be an integer
- AzureException ContextWindowExceededError - {message}
- api base needs to be a string. api_base={api_base}
- dynamic_api_key needs to be a string. Got type={type(dynamic
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/248542cb542c87a9.
Report an issue: GitHub.