Azure provider: cannot target chat/completions (404 on responses); need explicit config/docs for Azure wire and path construction
Resolved 💬 17 comments Opened Aug 8, 2025 by santiago-afonso Closed Nov 28, 2025
What version of Codex is running?
codex-cli 0.19.0
Which model were you using?
gpt-5
What platform is your computer?
Linux 6.6.87.1-microsoft-standard-WSL2 x86_64 x86_64
What steps can reproduce the bug?
Environment
- Codex CLI: v0.19 (Rust)
- OS: Linux (x86-64)
- Auth: Entra ID (AAD) access token via client credentials (raw JWT in env var)
- Azure target: Azure OpenAI fronted by API Management (APIM)
- Config method:
~/.codex/config.toml+--profile - Model: Azure deployment name (not base model)
Summary
Codex CLI’s Azure provider appears to call the Responses API path:
/openai/deployments/{deployment}/responses?api-version=...
Our APIM only exposes Chat Completions:
/openai/deployments/{deployment}/chat/completions?api-version=...
Result: Codex returns 404 Not Found consistently, while curl and the Python SDK succeed using chat/completions.
What works
- Mint Entra ID access token (client credentials).
curltoPOST .../openai/deployments/<DEPLOY>/chat/completions?api-version=2025-04-01-previewreturns 200 OK with a normal response.- Python
AzureOpenAI+chat.completions.create(...)returns 200 OK against the same endpoint.
What fails
- Codex CLI (with Azure provider + profile) returns 404 Not Found repeatedly.
- Hitting
.../openai/deployments/<DEPLOY>/responses?api-version=...withcurlalso returns 404 on our APIM (that path isn’t exposed).
Minimal (sanitized) config
# ~/.codex/config.toml
model_provider = "azure"
model = "<AZURE_DEPLOYMENT_NAME>"
[model_providers.azure]
name = "Azure"
# Base ends in /openai so provider appends /deployments/{model}/...
base_url = "https://<YOUR-APIM-DOMAIN>/openai"
query_params = { api-version = "2025-04-01-preview" }
# We need to force Chat Completions here, but there’s no documented knob.
# (Tried variations; CLI still hits /responses.)
[profiles.az-qa]
model_provider = "azure"
model = "<AZURE_DEPLOYMENT_NAME>"
Invocation
export AZURE_OPENAI_API_KEY="<RAW_JWT_FROM_AAD>" # no "Bearer " prefix
codex --profile az-qa -m "<AZURE_DEPLOYMENT_NAME>" "say hello"
# => 404 Not Found
Logs (excerpt)
... INFO BackgroundEvent: stream error: unexpected status 404 Not Found: {"statusCode":404,"message":"Resource not found"}
... WARN stream disconnected - retrying ...
Repro (working vs failing)
# Working (Chat Completions)
curl -sS -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-X POST "https://<YOUR-APIM-DOMAIN>/openai/deployments/<DEPLOY>/chat/completions?api-version=2025-04-01-preview" \
-d '{"messages":[{"role":"user","content":"ping"}]}'
# => 200 OK
# Failing (Responses)
curl -sS -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-X POST "https://<YOUR-APIM-DOMAIN>/openai/deployments/<DEPLOY>/responses?api-version=2025-04-01-preview" \
-d '{"input":[{"role":"user","content":"ping"}]}'
# => 404 Not Found
Expected
- Either:
- A documented configuration option to select the Azure wire:
- e.g.,
wire_api = "chat.completions"vswire_api = "responses"in the Azure provider block; or
- A path-template override (e.g.,
path_template = "/deployments/{model}/chat/completions")
- And documentation that clearly shows:
base_urlmust end with/openai.modelmust be the Azure deployment name.- How to set
api-versionviaquery_params. - How to provide an AAD access token (raw JWT vs
"Bearer "), plus whether API keys are supported and which header the CLI sends.
Actual
- CLI appears to target
/responseswith no way (documented) to forcechat/completions, leading to 404s on Azure setups that only expose Chat Completions via APIM.
Requests
- Bug/feature: Add a documented way to select the Azure wire (Chat Completions vs Responses) or to override the path template for Azure.
- Docs: Provide an end-to-end Azure section with:
- Minimal TOML for Azure.
- AAD Device Code and Client Credentials examples that mint a token and run Codex.
- Exact path shapes Codex will call for each wire.
api-versionconfiguration.- Troubleshooting guidance (401 vs 404, where logs live, how to confirm the final URL).
Why this matters
Many Azure/APIM deployments expose Chat Completions but not Responses. Without a documented knob to choose the wire (or override the path), Codex can’t interoperate with otherwise standard Azure OpenAI setups.
Thanks!
What is the expected behavior?
_No response_
What do you see instead?
_No response_
Additional information
_No response_
17 Comments
I have exactly this problem aswell. Very nicely formulated.
I get a '🖐 builder error' but curls just fine because I'm using chat completions with API keys
Guess who wrote it
@santiago-afonso your
config.tomlsection needs to look something like this:The
modelvalue in theprofilesblock is only used internally to the cli to lookup model parameters (like context window size), so i recommend it matches one of the values fromcodex-rs/core/src/openai_model_info.rs.Does not work. Though there are no 400/404 errors with this config, the commands do not do anything. Input a command - it shows working for a couple of second and dies out. This is a consistent problem with azure. Looks like use of azure is being discouraged.
Thanks for your comment. My organization works with bearer tokens, not API keys, so this wouldn't solve the issue.
This works with bearer tokens too (https://github.com/openai/codex/blob/main/codex-rs/core/src/model_provider_info.rs#L98-L117), the value of
env_keyis passed withAuthorization: Bearer <token>.I've been using this for several weeks.
I don't get the feeling that it's discouraged, there are definitely still occasional issues and documentation is lacking. Codex is still a research preview. If you enable
RUST_LOG=traceenv variable you might get more helpful output.Still stuck probably holding it wrong. I've tried multiple permutations of the variables I've seen in other closed issues using Azure Open AI with chat completions and a geographical region subdomain. Always this builder error though.
<img width="1081" height="154" alt="Image" src="https://github.com/user-attachments/assets/5ef65904-d722-42fa-902a-f4880292f56d" />
using
RUST_LOG=1 codexcat ~/.codex/log/codex-tui.logI get a '🖐 builder error'
curlworks and returns a "Hello how can I help..."I am on the same boat, tried countless permutations, curl works, codex doesn't. First, it took hours of trial and error to get
codexto post to the correct URL (thanks @jepio for the RUST_LOG tip). Below is the writeup.Codex CLI v0.20 ↔ Azure OpenAI via APIM (Entra ID): What Worked vs. What Didn’t
TL;DR (most relevant):
Codex CLI succeeds only when the request path contains
/openai/deployments/{deployment}/chat/completionsand an explicitapi-version. Transport/auth work; the TUI render is flaky (completion arrives, but nothing is painted). Use plain stdout as a workaround.---
Working configurations (observed)
1) Direct HTTP (control tests)
POST <APIM_BASE>/openai/deployments/<DEPLOYMENT>/chat/completions?api-version=...✓
200 OKwithmodel: gpt-5-YYYY-MM-DD.chat.completions.create) with the same deploymented path + JWT.✓
200 OK.2) Codex CLI v0.20 (transport/auth OK; TUI flaky)
base_urlalready includes/openai/deployments/<DEPLOYMENT>, plus:wire_api = "chat"query_params = { "api-version" = "<API_VERSION>" }(key must be quoted)requires_openai_auth = falseenv_key = "AZURE_OPENAI_API_KEY"and/orenv_http_headers = { "Authorization" = "Bearer ${AZURE_OPENAI_API_KEY}" }POST .../deployments/<DEPLOYMENT>/chat/completions?api-version=...Output item ... "Hello! How can I help today?"Minimal known-good provider snippet (redacted/templated):
Runtime:
---
Not working (observed) & symptoms
base_url = "<APIM_BASE>/openai"(no/deployments/<DEPLOYMENT>)→ 404 Not Found from APIM.
wire_api = "responses"→ 404 (APIM does not expose that route here).
api-versionOmit query param or mis-name the key (unquoted
api-version)→ 404. (Quoting the hyphenated key is required.)
model_provider = "..."at top level→ “Model provider … not found.”
azureproviders (or a stub at top) sometimes caused Codex to fall back to api.openai.com→ 401 Unauthorized (“You didn’t provide an API key”), even though a valid JWT was present.
Transport succeeds (SSE, “Output item …”), but no text is shown in the UI.
→ This is display-only; completions are produced.
---
Known-good patterns (keep these)
base_url:.../openai/deployments/<DEPLOYMENT>query_params = { "api-version" = "<API_VERSION>" }requires_openai_auth = falseand (optionally)env_http_headers.Authorization = "Bearer ${AZURE_OPENAI_API_KEY}".your-org) and define it once at top level; reference it from the profile.---
Negative controls (useful for repro issues)
base_url = "<APIM_BASE>/openai"(no/deployments/...) → expect 404.api-version→ expect 404.OPENAI_*envs set or let Codex pick the OpenAI default base → expect 401 toapi.openai.com.---
Checklist to keep it green
base_urlincludes/openai/deployments/<DEPLOYMENT>wire_api = "chat"query_params."api-version"present and quotedrequires_openai_auth = falseAuthorization: Bearer <JWT>is sent (viaenv_keyand/orenv_http_headers)OPENAI_*env varsThis reflects only what we actually tried and observed.
I respect your feeling. but the fact of the matter is azure support was broken in:
0.05
0.10
0.15 and still in
0.20
so make of it whatever you will
This works for me!
This config worked for me with the responses API (Make sure to replace the resource and configure the
AZURE_API_KEYas an environment variable)Spent a good amount of time trying to make this work with the Rust client + Azure.
It seems that when using Responses API sets the reasoning_effort parameter into the API call by default, and non-reasoning models like GPT-4.1 don't work.
Below is configuration which defines two Azure providers: one for Chat Completions and one for Responses API, and then in the profiles you combine the correct provider to the specific model:
With this example, running GPT-4.1 with Chat Completions API:
codex --profile=gpt-41and GPT-5 with Responses API:
codex --profile=gpt-5.This worked for me
Hi guys,
I ran into the same issue, and finally gemini 2.5 inside the codex codebase was able to find the correct configuration to run oss-120b on chat completion inside codex.
I think the magic trick was simply to set the api-version as "preview" (which of course is absolutely never disclosed in Azure official doc).
Here it is. Adapt as needed.
Same problem!!!
I am trying to use Azure Chat Completion model - Kimi K2.6 in OpenAI Codex CLI but was not working.