I ran into a failure that looked like an authentication problem at first:
unexpected status 401 Unauthorized
The setup was Codex against Tencent Cloud LKEAP Token Plan, using an OpenAI-compatible Chat Completions endpoint.
The important clue was not the 401. It was the final URL:
https://api.lkeap.cloud.tencent.com/plan/v3/chat/completions/responses
That URL shape is already wrong.
The config that caused it
The provider entry looked roughly like this:
[model_providers.custom]
name = "custom"
wire_api = "responses"
requires_openai_auth = true
base_url = "https://api.lkeap.cloud.tencent.com/plan/v3/chat/completions"
The mistake is subtle.
The Tencent endpoint in this setup is Chat Completions-style:
/plan/v3/chat/completions
But newer Codex expects a Responses API-style provider when wire_api = "responses" is used. So Codex appended /responses to a base URL that already ended in /chat/completions.
That produced:
/plan/v3/chat/completions/responses
At that point, rotating the API key is unlikely to help. The request is already going to the wrong protocol path.
Why not switch Codex back to Chat Completions?
That was the next thing I checked.
The newer Codex configuration rejects wire_api = "chat":
invalid configuration: `wire_api = "chat"` is no longer supported.
How to fix: set `wire_api = "responses"` in your provider config.
So this is not just a missing slash or a bad base URL. It is a protocol mismatch:
- Codex wants to speak Responses API.
- The LKEAP endpoint I was using speaks Chat Completions.
- "OpenAI-compatible" does not automatically mean "compatible with every OpenAI client mode."
That last point is the real lesson.
My debugging order now
For this class of issue, I would check things in this order:
- Inspect the final request URL.
- Confirm the client's wire protocol.
- Confirm the upstream endpoint shape.
- Only then spend time on keys and permissions.
If the URL contains patterns like these, stop and look at path composition first:
/chat/completions/responses
/v1/v1
/responses/chat/completions
The status code may be a symptom. The URL shape is often the evidence.
Workaround: local protocol adapter
The workaround I tested toward was a small local Node.js proxy.
Codex calls a local Responses-shaped endpoint:
http://127.0.0.1:15722/v1/responses
The local proxy converts that into a Chat Completions request and forwards it to:
https://api.lkeap.cloud.tencent.com/plan/v3/chat/completions
The Codex config then points to the local proxy:
model_provider = "tencent_lkeap_proxy"
model = "glm-5.1"
disable_response_storage = true
[model_providers.tencent_lkeap_proxy]
name = "Tencent LKEAP via local Responses proxy"
wire_api = "responses"
base_url = "http://127.0.0.1:15722/v1"
requires_openai_auth = true
env_key = "OPENAI_API_KEY"
The real Tencent key stays in the proxy process environment:
$env:TENCENT_LKEAP_API_KEY="REDACTED"
$env:TENCENT_LKEAP_MODEL="glm-5.1"
node tools\codex-responses-to-chat-proxy.mjs
Codex still expects an OpenAI auth variable for this provider shape, so I used a local dummy value:
$env:OPENAI_API_KEY="local-proxy-dummy"
The proxy ignores that dummy value and uses TENCENT_LKEAP_API_KEY upstream.
Boundary
I would not describe this as a complete drop-in replacement.
What was verified in the original debugging record:
- the failure path was identified
- the local proxy script was created
-
node --checkpassed
Still to verify:
- full end-to-end smoke test with a real LKEAP key
- streaming behavior under longer tasks
- Codex tool-call traffic
- cancellation, timeout, and error mapping
That distinction matters. A protocol adapter can be useful, but it should be treated as an adapter to harden, not as magic compatibility.
The practical takeaway:
When an AI coding tool fails against an "OpenAI-compatible" endpoint, do not ask only whether the key is valid. Ask whether the client and server are actually speaking the same API shape.
Original version:
https://kunpeng-ai.com/en/blog/codex-lkeap-protocol-path-debugging/




Top comments (0)