Skip to content

codex: every request to an Azure OpenAI Model Provider Service 400s — empty tool description rejected by Azure #323

Description

@NeilMazumdar

Summary

Every Codex request through an Azure OpenAI Model Provider Service fails with HTTP 400. Codex ≥ 0.147 packages its built-in tools as an input-item tool whose description is an empty string, and the Azure OpenAI Responses API rejects an empty description where OpenAI direct accepts it. Codex is unusable against an Azure OpenAI MPS as a result — the very first turn fails, with or without MCP servers.

ERROR: {"error_code":"BAD_REQUEST","message":"Model Provider Service returned error with status code 400:
Invalid 'input[0].tools[0].description': empty string. Expected a string with minimum length 1,
but got an empty string instead. ...","details":[{"reason":"MODEL_PROVIDER_ERROR",
"metadata":{"provider":"azure_openai","upstream_status":"400",
"upstream_body":"{\"error\":{\"message\":\"Invalid 'input[0].tools[0].description': empty string...\",
\"type\":\"invalid_request_error\",\"param\":\"input[0].tools[0].description\",\"code\":\"empty_string\"}}"}}]}

Versions

ucode 0.0.0+192.gadedcb1
codex-cli 0.147.0
Provider EXTERNAL_MODEL_PROVIDER_TYPE_AZURE_OPENAI MPS, target is an Azure deployment
Route POST {workspace}/ai-gateway/codex/v1/responses, wire_api = "responses"

Root cause

Captured the request Codex actually sends by pointing model_providers.ucode-databricks.base_url at a local listener. The payload has no top-level tools; instead input[0] carries:

{"type": "namespace", "name": "functions", "description": ""}

Azure OpenAI rejects description: "". The gateway forwards the body verbatim, so it surfaces as MODEL_PROVIDER_ERROR.

Minimal proof it is this one field

Replayed the captured request against the same MPS twice, byte-identical except for that string:

Request Result
input[0].tools[0].description = "" (exactly what Codex sends) 400 empty_string
same request, description = "Shell and patch tools." 200, normal completion

A local proxy that fills only empty tool descriptions and forwards everything else untouched makes Codex work end-to-end against the Azure MPS, including tool calls (shell exec) and multi-turn.

Ruled out

  • MCP servers — -c mcp_servers={} fails identically; also reproduced with no MCP servers configured.
  • include_apply_patch_tool=false, tools.apply_patch=false, experimental_use_freeform_apply_patch=false, tools.view_image=false — all still 400.
  • MPS native_api_types — the Responses API works fine through this MPS; a hand-built Responses request with a valid tool returns 200.
  • Not an auth or routing problem: ucode auth-token works and the model resolves (model: <azure-deployment>, provider: ucode-databricks).

Suggested fix

The gateway is the natural place — it already knows the target is azure_openai, and normalising an empty description to a non-empty placeholder for Azure targets is a narrow, contained change. Alternatives are a fix in Codex (don't emit an empty description) or waiting on Azure to relax, neither of which ucode controls.

Filed separately: #324 (MPS model naming) and #325 (--dry-run side effects).

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions