Azure AI Foundry models (/openai/v1/responses) fail with 400 Invalid value and 400 The provided data does not match the expected schema across all GPT-5.x deployments
Summary
OpenClaw v2026.6.1 (and v2026.5.x) cannot successfully complete a single round-trip with Azure AI Foundry-hosted OpenAI models (GPT-5.2, GPT-5.4, GPT-5.4-pro, GPT-5.5) when using api: "openai-responses". Every call fails with a 400 schema validation error from Azure. This makes OpenClaw effectively unusable with the standard Microsoft Foundry deployment of OpenAI models.
The same Azure endpoints accept hand-crafted curl requests successfully — so this is a payload serialization bug inside OpenClaw's openai-responses transport when talking to Azure Foundry's /openai/v1/responses endpoint.
I also see two flavours of the error depending on the request:
400 Invalid value: ''. Supported values are: 'apply_patch_call', 'apply_patch_call_output', 'code_interpreter_call', 'compaction', 'computer_call', 'computer_call_output', 'custom_tool_call', 'custom_tool_call_output', 'file_search_call', 'function_call', 'function_call_output', 'image_generation_call', 'item_reference', 'local_shell_call', 'local_shell_call_output', 'mcp_approval_request', 'mcp_approval_response', 'mcp_call', 'mcp_list_tools', 'message', 'reasoning', 'shell_call', 'shell_call_output', 'tool_search_call', 'tool_search_output', and 'web_search_call'.
→ Strongly suggests OpenClaw is emitting an item with type: "" (empty string) somewhere in the input[] array.
400 The provided data does not match the expected schema [Request ID: ...]
→ Different request body, same provider, also rejected.
Switching to api: "openai-completions" against /openai/v1/chat/completions on the same Azure Foundry resource succeeds with curl for both GPT-5.2 and GPT-5.5, but OpenClaw still fails (different code path also broken — see Run 6).
Environment
- OpenClaw version: tested on
2026.5.2, 2026.5.12, 2026.5.28, 2026.6.1 (current)
- Node.js: v22.22.3
- OS: Windows 11 (native install via
npm install -g openclaw)
- Channels enabled: Telegram (allowlist), WhatsApp
- Active model provider: custom
openai-responses provider pointed at Azure AI Foundry
- Auth:
api-key header
Azure resources tested (all fail)
| Resource |
Region |
Type |
Deployments tested |
<RESOURCE_A>.services.ai.azure.com (project: <PROJECT>) |
eastus2 |
AIServices (Foundry project endpoint) |
gpt-5.2, gpt-5.4-pro, gpt-5.5 |
<RESOURCE_B>.cognitiveservices.azure.com |
eastus |
AIServices |
gpt-5.2, gpt-5.4, gpt-5.5 |
<RESOURCE_C>.cognitiveservices.azure.com |
eastus2 |
AIServices |
gpt-5.3-codex |
<RESOURCE_D>.cognitiveservices.azure.com |
|
AIServices |
gpt-5.2 |
All four fail in identical ways when OpenClaw is the client. Only differences are the deployment IDs.
Provider config (representative)
~/.openclaw/openclaw.json — only relevant blocks shown:
{
"models": {
"providers": {
"azure-foundry": {
"baseUrl": "https://<RESOURCE>.services.ai.azure.com/openai/v1",
"apiKey": "${AZURE_FOUNDRY_API_KEY}",
"api": "openai-responses",
"headers": {
"api-key": "${AZURE_FOUNDRY_API_KEY}"
},
"models": [
{ "id": "gpt-5.5", "name": "GPT 5.5 (foundry)", "reasoning": true, "input": ["text","image"], "contextWindow": 200000, "maxTokens": 65536 },
{ "id": "gpt-5.2", "name": "GPT 5.2 (foundry)", "reasoning": true, "input": ["text","image"], "contextWindow": 200000, "maxTokens": 16384 },
{ "id": "gpt-5.4-pro", "name": "GPT 5.4 Pro (foundry)", "reasoning": true, "input": ["text","image"], "contextWindow": 200000, "maxTokens": 32768 }
]
}
}
},
"agents": {
"defaults": {
"model": {
"primary": "azure-foundry/gpt-5.5",
"fallbacks": ["azure-foundry/gpt-5.2"]
},
"thinkingDefault": "off"
}
}
}
The same shape was tested with "api": "azure-openai-responses" (also fails with 400 Missing required query parameter: api-version because the Foundry /v1 path explicitly disallows the api-version query param) and with "api": "openai-completions" against /chat/completions (also fails — see Run 6 below).
Additional combinations tried:
baseUrl with and without /v1
baseUrl with /openai/deployments/<model> (legacy Azure path) — returns 404 on Foundry
baseUrl with the project-scoped path /api/projects/<project>/openai/v1 — same 400
- Auth via
api-key header AND via Authorization: Bearer ... (both accepted by Azure, both rejected by OpenClaw's payload)
headers.api-key set explicitly in the provider block
- Removing and re-adding
auth-profiles.json entries
- Wiping
~/.openclaw/agents/main/sessions/* between every test
- Hard restart of the gateway process (not just hot reload)
- Scoping
api-version injection via a custom NODE_OPTIONS --require patch (works for azure-openai-responses URL form, doesn't help for /v1 form because Azure rejects the query param entirely on /v1)
Repro: control via curl (works)
These all return HTTP 200 with valid responses (run from the same Windows host):
# /v1/responses with api-key header (no api-version)
curl -X POST "https://<RESOURCE>.services.ai.azure.com/api/projects/<PROJECT>/openai/v1/responses" \
-H "api-key: <AZURE_FOUNDRY_API_KEY>" \
-H "Content-Type: application/json" \
-d '{"model":"gpt-5.5","input":"say hello"}'
# -> 200, response.output[0].content[0].text = "Hello!"
# /v1/chat/completions with api-key header
curl -X POST "https://<RESOURCE>.services.ai.azure.com/openai/v1/chat/completions" \
-H "api-key: <AZURE_FOUNDRY_API_KEY>" \
-H "Content-Type: application/json" \
-d '{"model":"gpt-5.5","messages":[{"role":"user","content":"hi"}],"max_completion_tokens":100}'
# -> 200
# Same with Bearer auth - also 200
curl -X POST "https://<RESOURCE>.services.ai.azure.com/openai/v1/chat/completions" \
-H "Authorization: Bearer <AZURE_FOUNDRY_API_KEY>" \
-H "Content-Type: application/json" \
-d '{"model":"gpt-5.5","messages":[{"role":"user","content":"hi"}],"max_completion_tokens":100}'
So the endpoints work, the key works, the auth works, and the URL is correct. The problem is the body OpenClaw constructs.
Repro: via OpenClaw (fails every time)
- Configure
azure-foundry provider as above.
- Set
agents.defaults.model.primary = "azure-foundry/gpt-5.5" (or 5.2, or 5.4-pro — all behave the same).
- Start the gateway (
schtasks /Run /TN "OpenClaw Gateway" on Windows).
- Send any message (even a 5-char "hello") on any channel (Telegram, web, etc.).
- Observe a
400 Invalid value: '' or 400 The provided data does not match the expected schema from Azure in the logs.
- OpenClaw's failover then tries fallback models on the same provider, all fail the same way, request ultimately surfaces "All models failed" to the user.
Concrete log excerpts
Run 1 — api: "openai-responses" against /openai/v1/responses, GPT-5.5
[telegram] Inbound message telegram:<USER_ID> -> @<BOT_NAME> (direct, 5 chars)
[agent/embedded] [trace:embedded-run] startup stages: ... model-resolution:5878ms,auth:4965ms ...
[openai-transport] [responses] error provider=azure-foundry api=openai-responses model=gpt-5.5
name=Error status=400 code=invalid_value type=invalid_request_error
message=400 Invalid value: ''. Supported values are:
'apply_patch_call', 'apply_patch_call_output', 'code_interpreter_call', 'compaction',
'computer_call', 'computer_call_output', 'custom_tool_call', 'custom_tool_call_output',
'file_search_call', 'function_call', 'function_call_output', 'image_generation_call',
'item_reference', 'local_shell_call', 'local_shell_call_output',
'mcp_approval_request', 'mcp_approval_response', 'mcp_call', 'mcp_list_tools',
'message', 'reasoning', 'shell_call', 'shell_call_output',
'tool_search_call', 'tool_search_output', 'web_search_call'.
[telegram] embedded run agent end: isError=true model=gpt-5.5 provider=azure-foundry
error=LLM request failed: provider rejected the request schema or tool payload.
[model-fallback/decision] decision=candidate_failed requested=azure-foundry/gpt-5.5
reason=format next=azure-foundry/gpt-5.2
(Each fallback fails identically. Final error to user: All models failed (3) ....)
Run 2 — api: "openai-responses", GPT-5.4-pro and GPT-5.2 same provider
[openai-transport] [responses] error provider=azure-foundry api=openai-responses model=gpt-5.4-pro
status=400 code=invalid_payload type=invalid_request_error
message=400 The provided data does not match the expected schema [Request ID: 942748853d571d96e5807c45920f4eb4]
...
[openai-transport] [responses] error provider=azure-foundry api=openai-responses model=gpt-5.2
status=400 code=invalid_payload type=invalid_request_error
message=400 The provided data does not match the expected schema [Request ID: 35fae76995a7bbc4c745aa3707edbfb0]
Two different error codes (invalid_value vs invalid_payload) suggest OpenClaw constructs at least two distinct invalid payload shapes depending on whether tools/reasoning/memory items are present.
Run 3 — api: "azure-openai-responses" (built-in Azure provider type)
[openai-transport] [responses] error provider=azure-foundry api=azure-openai-responses model=gpt-5.5
status=400
message=400 Missing required query parameter: api-version
So the built-in azure-openai-responses transport doesn't add api-version to the request, but the /openai/v1/responses endpoint rejects requests without it. The azure-openai-responses transport seems hard-coded to not append api-version while still using the rest of the Azure-specific framing.
If I instead point the same provider at the legacy /openai/deployments/<id>/responses?api-version=... URL with azure-openai-responses, the request now ships api-version correctly — but the deployment-based Responses endpoint returns 404 on the Foundry resource because Foundry only exposes the project-scoped /openai/v1/responses path. So the azure-openai-responses transport is hard-wired for an endpoint shape Foundry no longer ships.
Run 4 — api: "openai-completions" against /openai/v1/chat/completions
[openai-transport] error provider=azure-foundry api=openai-responses model=gpt-5.2
status=400 code=invalid_payload
message=400 The provided data does not match the expected schema [Request ID: ...]
Note: log line still says api=openai-responses even though config was changed to openai-completions. Either the change didn't take effect (no hot reload for api field?) or the transport selection ignores the override. This needs verification — but the request still fails with the same schema rejection.
What this looks like on the wire
I haven't proxied the actual request body yet (the gateway uses Node's native fetch + streaming, hard to MitM without modifying source), but the Azure error Invalid value: ''. Supported values are: ['message', 'function_call', 'reasoning', ...] strongly indicates OpenClaw is sending something like:
{
"model": "gpt-5.5",
"input": [
{ "type": "message", "role": "user", "content": [...] },
{ "type": "", ...something... } // <- this is what Azure rejects
]
}
This is consistent with how OpenClaw passes prior session compaction items, reasoning continuations, or tool outputs back to the model — one of those item builders likely outputs type as an empty string when the corresponding upstream field is missing.
What I tried (none worked)
- Upgrading OpenClaw
2026.2.23 → 2026.5.12 → 2026.5.28 → 2026.6.1.
- Switching between 4 different Azure resources (Foundry project endpoint, two
AIServices cognitiveservices endpoints, and an AIServices in a different region).
- Switching across 5 model deployments (gpt-5.2, gpt-5.3-codex, gpt-5.4, gpt-5.4-pro, gpt-5.5).
- Toggling between
openai-responses, azure-openai-responses, and openai-completions API types.
- Multiple
baseUrl shapes:
https://<acct>.cognitiveservices.azure.com/openai
https://<acct>.cognitiveservices.azure.com/openai/v1
https://<acct>.services.ai.azure.com/openai/v1
https://<acct>.services.ai.azure.com/api/projects/<project>/openai/v1
https://<acct>.cognitiveservices.azure.com/openai/deployments/<model> (legacy)
- Auth via
api-key header, via Authorization: Bearer ..., both at the same time.
- Setting
headers.api-key explicitly in the provider config.
- Hot reload, soft restart (
openclaw gateway restart), hard kill + schtasks restart, full reinstall (openclaw gateway install --force).
- Wiping all sessions (
~/.openclaw/agents/main/sessions/*) between attempts.
thinkingDefault set to max, off, removed entirely.
- NODE preload patch that adds
?api-version=2025-03-01-preview to all outgoing requests for the legacy provider type.
Only direct curl calls succeed.
Impact
- Telegram channel users get either
LLM request failed: provider rejected the request schema or tool payload or a 2–3 minute hang followed by All models failed.
- WhatsApp channel has its own packaging warning that prevents it from loading at all on v2026.5.x and v2026.6.1 (
installed plugin package requires compiled runtime output for TypeScript entry index.ts: expected ./dist/index.js ...) — separate issue, but worth mentioning since it removes the only working channel as a workaround.
- Memory search, voice, image, and tool features are unusable end-to-end because every model call dies before the first token.
Asks
- Fix the
openai-responses transport to never emit {"type": ""} items in input[]. Either omit the field, or default to a valid enum value, or drop the item.
- Fix the
azure-openai-responses transport to support Foundry's /openai/v1/responses path. Specifically:
- Don't inject
api-version on /openai/v1/... URLs (Azure rejects it there).
- Do inject
api-version on /openai/deployments/.../responses URLs (Azure requires it there).
- Detection should be path-based, not host-based.
- Make
api field hot-reloadable, or surface a clear warning when it isn't (Run 4 above suggests the api selection is sticky after process start even though other model fields hot-reload fine).
- Document the supported endpoint shapes for Azure AI Foundry explicitly — Microsoft has been steadily migrating from deployment-based to project-based to
/v1-style paths and OpenClaw's docs don't currently cover any of these clearly.
- Optional: a
requestBodyLogging: true knob on providers for one-off debugging would have made this trivial to root-cause from outside.
Willing to help
Happy to:
- Capture and attach the actual outgoing request body if you can point me at the right OpenClaw source file (or merge a
--debug-llm-payload flag).
- Test patches against my Foundry resources.
- Share full uncut logs and exact
openclaw.json (private values redacted).
Thanks for the project — this is the one blocker keeping it from being our team's daily driver.
Azure AI Foundry models (
/openai/v1/responses) fail with400 Invalid valueand400 The provided data does not match the expected schemaacross all GPT-5.x deploymentsSummary
OpenClaw v2026.6.1 (and v2026.5.x) cannot successfully complete a single round-trip with Azure AI Foundry-hosted OpenAI models (GPT-5.2, GPT-5.4, GPT-5.4-pro, GPT-5.5) when using
api: "openai-responses". Every call fails with a 400 schema validation error from Azure. This makes OpenClaw effectively unusable with the standard Microsoft Foundry deployment of OpenAI models.The same Azure endpoints accept hand-crafted
curlrequests successfully — so this is a payload serialization bug inside OpenClaw'sopenai-responsestransport when talking to Azure Foundry's/openai/v1/responsesendpoint.I also see two flavours of the error depending on the request:
400 Invalid value: ''. Supported values are: 'apply_patch_call', 'apply_patch_call_output', 'code_interpreter_call', 'compaction', 'computer_call', 'computer_call_output', 'custom_tool_call', 'custom_tool_call_output', 'file_search_call', 'function_call', 'function_call_output', 'image_generation_call', 'item_reference', 'local_shell_call', 'local_shell_call_output', 'mcp_approval_request', 'mcp_approval_response', 'mcp_call', 'mcp_list_tools', 'message', 'reasoning', 'shell_call', 'shell_call_output', 'tool_search_call', 'tool_search_output', and 'web_search_call'.→ Strongly suggests OpenClaw is emitting an item with
type: ""(empty string) somewhere in theinput[]array.400 The provided data does not match the expected schema [Request ID: ...]→ Different request body, same provider, also rejected.
Switching to
api: "openai-completions"against/openai/v1/chat/completionson the same Azure Foundry resource succeeds withcurlfor both GPT-5.2 and GPT-5.5, but OpenClaw still fails (different code path also broken — see Run 6).Environment
2026.5.2,2026.5.12,2026.5.28,2026.6.1(current)npm install -g openclaw)openai-responsesprovider pointed at Azure AI Foundryapi-keyheaderAzure resources tested (all fail)
<RESOURCE_A>.services.ai.azure.com(project:<PROJECT>)<RESOURCE_B>.cognitiveservices.azure.com<RESOURCE_C>.cognitiveservices.azure.com<RESOURCE_D>.cognitiveservices.azure.comAll four fail in identical ways when OpenClaw is the client. Only differences are the deployment IDs.
Provider config (representative)
~/.openclaw/openclaw.json— only relevant blocks shown:{ "models": { "providers": { "azure-foundry": { "baseUrl": "https://<RESOURCE>.services.ai.azure.com/openai/v1", "apiKey": "${AZURE_FOUNDRY_API_KEY}", "api": "openai-responses", "headers": { "api-key": "${AZURE_FOUNDRY_API_KEY}" }, "models": [ { "id": "gpt-5.5", "name": "GPT 5.5 (foundry)", "reasoning": true, "input": ["text","image"], "contextWindow": 200000, "maxTokens": 65536 }, { "id": "gpt-5.2", "name": "GPT 5.2 (foundry)", "reasoning": true, "input": ["text","image"], "contextWindow": 200000, "maxTokens": 16384 }, { "id": "gpt-5.4-pro", "name": "GPT 5.4 Pro (foundry)", "reasoning": true, "input": ["text","image"], "contextWindow": 200000, "maxTokens": 32768 } ] } } }, "agents": { "defaults": { "model": { "primary": "azure-foundry/gpt-5.5", "fallbacks": ["azure-foundry/gpt-5.2"] }, "thinkingDefault": "off" } } }The same shape was tested with
"api": "azure-openai-responses"(also fails with400 Missing required query parameter: api-versionbecause the Foundry/v1path explicitly disallows theapi-versionquery param) and with"api": "openai-completions"against/chat/completions(also fails — see Run 6 below).Additional combinations tried:
baseUrlwith and without/v1baseUrlwith/openai/deployments/<model>(legacy Azure path) — returns 404 on FoundrybaseUrlwith the project-scoped path/api/projects/<project>/openai/v1— same 400api-keyheader AND viaAuthorization: Bearer ...(both accepted by Azure, both rejected by OpenClaw's payload)headers.api-keyset explicitly in the provider blockauth-profiles.jsonentries~/.openclaw/agents/main/sessions/*between every testapi-versioninjection via a customNODE_OPTIONS--requirepatch (works forazure-openai-responsesURL form, doesn't help for/v1form because Azure rejects the query param entirely on/v1)Repro: control via
curl(works)These all return
HTTP 200with valid responses (run from the same Windows host):So the endpoints work, the key works, the auth works, and the URL is correct. The problem is the body OpenClaw constructs.
Repro: via OpenClaw (fails every time)
azure-foundryprovider as above.agents.defaults.model.primary = "azure-foundry/gpt-5.5"(or 5.2, or 5.4-pro — all behave the same).schtasks /Run /TN "OpenClaw Gateway"on Windows).400 Invalid value: ''or400 The provided data does not match the expected schemafrom Azure in the logs.Concrete log excerpts
Run 1 —
api: "openai-responses"against/openai/v1/responses, GPT-5.5(Each fallback fails identically. Final error to user:
All models failed (3) ....)Run 2 —
api: "openai-responses", GPT-5.4-pro and GPT-5.2 same providerTwo different error codes (
invalid_valuevsinvalid_payload) suggest OpenClaw constructs at least two distinct invalid payload shapes depending on whether tools/reasoning/memory items are present.Run 3 —
api: "azure-openai-responses"(built-in Azure provider type)So the built-in
azure-openai-responsestransport doesn't addapi-versionto the request, but the/openai/v1/responsesendpoint rejects requests without it. Theazure-openai-responsestransport seems hard-coded to not appendapi-versionwhile still using the rest of the Azure-specific framing.If I instead point the same provider at the legacy
/openai/deployments/<id>/responses?api-version=...URL withazure-openai-responses, the request now shipsapi-versioncorrectly — but the deployment-based Responses endpoint returns404on the Foundry resource because Foundry only exposes the project-scoped/openai/v1/responsespath. So theazure-openai-responsestransport is hard-wired for an endpoint shape Foundry no longer ships.Run 4 —
api: "openai-completions"against/openai/v1/chat/completionsNote: log line still says
api=openai-responseseven though config was changed toopenai-completions. Either the change didn't take effect (no hot reload forapifield?) or the transport selection ignores the override. This needs verification — but the request still fails with the same schema rejection.What this looks like on the wire
I haven't proxied the actual request body yet (the gateway uses Node's native fetch + streaming, hard to MitM without modifying source), but the Azure error
Invalid value: ''. Supported values are: ['message', 'function_call', 'reasoning', ...]strongly indicates OpenClaw is sending something like:{ "model": "gpt-5.5", "input": [ { "type": "message", "role": "user", "content": [...] }, { "type": "", ...something... } // <- this is what Azure rejects ] }This is consistent with how OpenClaw passes prior session compaction items, reasoning continuations, or tool outputs back to the model — one of those item builders likely outputs
typeas an empty string when the corresponding upstream field is missing.What I tried (none worked)
2026.2.23→2026.5.12→2026.5.28→2026.6.1.AIServicescognitiveservices endpoints, and an AIServices in a different region).openai-responses,azure-openai-responses, andopenai-completionsAPI types.baseUrlshapes:https://<acct>.cognitiveservices.azure.com/openaihttps://<acct>.cognitiveservices.azure.com/openai/v1https://<acct>.services.ai.azure.com/openai/v1https://<acct>.services.ai.azure.com/api/projects/<project>/openai/v1https://<acct>.cognitiveservices.azure.com/openai/deployments/<model>(legacy)api-keyheader, viaAuthorization: Bearer ..., both at the same time.headers.api-keyexplicitly in the provider config.openclaw gateway restart), hard kill + schtasks restart, full reinstall (openclaw gateway install --force).~/.openclaw/agents/main/sessions/*) between attempts.thinkingDefaultset tomax,off, removed entirely.?api-version=2025-03-01-previewto all outgoing requests for the legacy provider type.Only direct
curlcalls succeed.Impact
LLM request failed: provider rejected the request schema or tool payloador a 2–3 minute hang followed byAll models failed.installed plugin package requires compiled runtime output for TypeScript entry index.ts: expected ./dist/index.js ...) — separate issue, but worth mentioning since it removes the only working channel as a workaround.Asks
openai-responsestransport to never emit{"type": ""}items ininput[]. Either omit the field, or default to a valid enum value, or drop the item.azure-openai-responsestransport to support Foundry's/openai/v1/responsespath. Specifically:api-versionon/openai/v1/...URLs (Azure rejects it there).api-versionon/openai/deployments/.../responsesURLs (Azure requires it there).apifield hot-reloadable, or surface a clear warning when it isn't (Run 4 above suggests theapiselection is sticky after process start even though other model fields hot-reload fine)./v1-style paths and OpenClaw's docs don't currently cover any of these clearly.requestBodyLogging: trueknob on providers for one-off debugging would have made this trivial to root-cause from outside.Willing to help
Happy to:
--debug-llm-payloadflag).openclaw.json(private values redacted).Thanks for the project — this is the one blocker keeping it from being our team's daily driver.