Fix Azure OpenAI 'Unrecognized request argument: functions'
The Azure OpenAI unrecognized request argument error for functions means your api-version or deployed model version does not support function calling. Use api-version 2024-06-01 or newer with a gpt-35-turbo 0613+, gpt-4 0613+ or gpt-4o deployment.
- The 400 error is about the Azure endpoint, api-version or model version, not about the shape of your JSON.
- Function calling needs api-version 2023-07-01-preview or later and a model such as gpt-35-turbo 0613+, gpt-4 0613+ or gpt-4o.
- Deployments on model versions 0301 or 0314 never accept functions or tools, so they must be redeployed on a newer version.
- Migrate from functions/function_call to tools/tool_choice; the same two causes explain 'Unrecognized request argument supplied: tools'.
- Pass the deployment name as model, set api_version on AzureOpenAI, and in LangChain use AzureChatOpenAI with bind_tools.
Why does Azure OpenAI say "Unrecognized request argument supplied: functions"?
The Azure OpenAI unrecognized request argument error appears because Azure validates every request body against the schema of the api-version in the query string, then against the capabilities of the model deployment. If either one has no `functions` field, the request is rejected with HTTP 400 and the message "Unrecognized request argument supplied: functions". Your JSON is not malformed; the endpoint simply does not know that field.
Function calling was added to the Azure chat completions API in api-version 2023-07-01-preview. Older versions such as 2022-12-01 and 2023-03-15-preview predate it, and models deployed from the 0301 or 0314 snapshots were trained without it. Code copied from the OpenAI docs usually works against api.openai.com because OpenAI has no api-version concept, which is why the failure only appears on Azure.
The same logic applies to `tools`. If you switch to the newer parameter and get "Unrecognized request argument supplied: tools", you are hitting the same two causes, not a new problem.
Symptom to cause to fix: a quick diagnosis table
Work down this table from the top. The first two rows explain most reports of this error.
| Symptom | Likely cause | Fix |
|---|---|---|
| 400 'Unrecognized request argument supplied: functions' or 'tools' | api-version older than 2023-07-01-preview | Set api_version to 2024-06-01 or newer |
| Same error with a new api-version | Deployment uses gpt-35-turbo 0301 or gpt-4 0314 | Redeploy or upgrade to 0613+ (or gpt-4o and later) |
| 404 DeploymentNotFound | Passed the OpenAI model name instead of the deployment name | Use model=<your deployment name> |
| Error only through a gateway or APIM | Gateway pins an old api-version or rewrites the URL | Check the policy and backend URL, then test the resource directly |
| Error only in LangChain | Using AzureOpenAI (completions class) or an old version | Use AzureChatOpenAI with azure_deployment and api_version |
| 400 on response_format json_schema or parallel_tool_calls | api-version or model too old for that feature | Use 2024-08-01-preview or later with a model that supports it |
| Error on /completions path | Calling the completions endpoint, not chat completions | Use client.chat.completions.create |
How do I set the api-version and Azure client correctly?
With openai 1.0 or newer, create an `AzureOpenAI` client and set `api_version` explicitly. The old `openai.api_type = 'azure'` globals belong to the 0.x SDK, which is also where `engine=` and `deployment_id=` came from. If `pip show openai` reports 0.x, upgrade with `pip install -U openai` and migrate your calls.
In LangChain, `api_version` can also come from the `OPENAI_API_VERSION` environment variable. A stale value exported in your shell or container image is a common reason a fix in code seems to be ignored.
from openai import AzureOpenAI
client = AzureOpenAI(
azure_endpoint="https://YOUR-RESOURCE.openai.azure.com",
api_key="...",
api_version="2024-06-01", # not 2023-03-15-preview or 2022-12-01
)
# Legacy 0.x SDK, for reference only:
# openai.api_type = "azure"
# openai.api_base = "https://YOUR-RESOURCE.openai.azure.com"
# openai.api_version = "2023-07-01-preview"
# openai.ChatCompletion.create(engine="my-deployment", ...) How do I check the deployed model version?
The api-version only unlocks the field; the deployment must also support the feature. Function calling needs gpt-35-turbo 0613 or later, gpt-4 0613 or later, or gpt-4o and later models. A deployment on 0301 or 0314 rejects `functions` and `tools` whatever the api-version.
Azure also expects the deployment name in the `model` argument. That name is whatever you typed when you created the deployment, and it may differ from the underlying model name.
- Open the Azure portal, go to your Azure OpenAI resource, and open the deployments list (Azure AI Foundry or Azure OpenAI Studio).
- Find your deployment and read its model name and model version columns.
- If the version is 0301 or 0314, create a new deployment on 0613 or later, or on gpt-4o or newer, and use its name as `model`.
- If the model is not offered in your region, pick a region that lists it; new versions often reach some regions later than others.
- Re-run the request and confirm the 400 is gone.
Legacy functions vs modern tools: before and after code
`functions` and `function_call` are deprecated in favour of `tools` and `tool_choice`. Each tool is wrapped as `{"type": "function", "function": {...}}`. Both forms work on Azure when the api-version and model allow them, but new code should use `tools`.
The schema in `parameters` must be valid JSON Schema with `type: object`, a `properties` map and a `required` list. The `description` fields are what the model reads when it decides which function to call, so write them precisely. Define the `tools` list once as a variable, as below, so every later request in the conversation can reuse it.
import json
schema = {
"type": "object",
"properties": {
"city": {"type": "string", "description": "City name, e.g. Paris"},
"unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
},
"required": ["city"],
}
messages = [{"role": "user", "content": "Weather in Paris?"}]
# BEFORE (legacy)
resp = client.chat.completions.create(
model="my-gpt4o-deployment",
messages=messages,
functions=[{"name": "get_weather", "description": "Get current weather", "parameters": schema}],
function_call="auto",
)
# AFTER (current): define the list once and reuse it in every request
tools = [{"type": "function", "function": {
"name": "get_weather",
"description": "Get current weather for a city",
"parameters": schema}}]
resp = client.chat.completions.create(
model="my-gpt4o-deployment", # deployment name
messages=messages,
tools=tools,
tool_choice="auto",
) How do I parse the tool call and send the result back?
The new response puts calls in `message.tool_calls`, while the legacy form uses `message.function_call`. The `arguments` value is a JSON string, not a dict, and the model can occasionally emit invalid JSON or omit a required key. Parse it defensively and validate before running anything with side effects.
Reply with one message of role `tool` per call, each carrying the matching `tool_call_id`. The legacy equivalent was role `function` with a `name`. Append the assistant message first, or the API rejects the sequence. This snippet continues from the previous one and reuses its `client`, `messages`, `tools` and `resp`.
# Continues the previous example: client, messages, tools and resp are already defined.
msg = resp.choices[0].message
if msg.tool_calls:
messages.append(msg) # assistant message containing all tool_calls
for call in msg.tool_calls:
try:
args = json.loads(call.function.arguments)
except json.JSONDecodeError:
args = None
if call.function.name != "get_weather" or not args or "city" not in args:
result = {"error": "invalid arguments"}
else:
result = {"city": args["city"], "temp_c": 18} # your real function here
messages.append({
"role": "tool",
"tool_call_id": call.id, # one tool message per call
"content": json.dumps(result),
})
# Only after every tool_call_id has been answered, ask for the final reply
final = client.chat.completions.create(
model="my-gpt4o-deployment", messages=messages, tools=tools)
print(final.choices[0].message.content)LangChain, gateways and a minimal curl test
In LangChain use `AzureChatOpenAI`, not `AzureOpenAI`, which wraps the completions endpoint. Pass `azure_deployment` and `api_version`, then call `bind_tools` instead of building `functions` by hand. If it still fails, test the raw endpoint, because an API Management gateway or proxy can pin an old api-version or forward to a different backend.
Structured outputs and parallel tool calls need newer versions. As a rule of thumb, use 2024-08-01-preview or later with a model that supports the feature, and treat anything older as unsupported for them.
# LangChain
# from langchain_openai import AzureChatOpenAI
# llm = AzureChatOpenAI(azure_deployment="my-gpt4o-deployment",
# api_version="2024-06-01", azure_endpoint="https://YOUR-RESOURCE.openai.azure.com")
# llm_with_tools = llm.bind_tools([get_weather])
# Minimal curl test (the URL shows the api-version being sent)
curl -i "https://YOUR-RESOURCE.openai.azure.com/openai/deployments/my-gpt4o-deployment/chat/completions?api-version=2024-06-01" \
-H "api-key: $AZURE_OPENAI_API_KEY" -H "Content-Type: application/json" \
-d '{"messages":[{"role":"user","content":"Weather in Paris?"}],"tools":[{"type":"function","function":{"name":"get_weather","parameters":{"type":"object","properties":{"city":{"type":"string"}},"required":["city"]}}}],"tool_choice":"auto"}'Common questions
Which Azure OpenAI api-version should I use for function calling?
The minimum is 2023-07-01-preview, but use a current GA version such as 2024-06-01 or newer. Features like structured outputs and parallel tool calls need newer versions such as 2024-08-01-preview or later.
Does gpt-35-turbo support function calling on Azure?
Yes, but only from model version 0613 onward. Deployments on 0301 reject both functions and tools, so redeploy on a newer version.
Can I still use functions instead of tools on Azure?
It works on supported api-versions and models, but it is deprecated. Move to tools and tool_choice, since new features are only added to that form.
Why do I get a 404 instead of the unrecognized argument error?
A 404 DeploymentNotFound usually means you passed the OpenAI model name rather than your deployment name, or the endpoint belongs to a different resource. Check the deployment name in the portal and the endpoint URL.
Why does the error persist after I changed api_version in code?
An OPENAI_API_VERSION environment variable, a gateway policy or a cached config may override it. Print the final request URL and confirm the api-version query string.