Codex + DeepSeek Setup Failing? Here’s Every Error We Hit (And How to Fix Each One)
If you’re routing Codex through CC Switch to run DeepSeek instead of GPT, you’ll likely run into five specific failures, in this order: a curl syntax mistake, a local proxy network mismatch, a provider config gap, an upstream protocol mismatch, and a malformed test request. This guide walks through each one, in the order they actually show up, with the reasoning behind each fix so you can diagnose new variants yourself.
Why DeepSeek Doesn’t Just Work With Codex Out of the Box
Codex talks to models using OpenAI’s Responses API by default — requests go to a /responses endpoint, and conversation content lives in an input field. DeepSeek’s public API, on the other hand, exposes the older Chat Completions format: requests go to /chat/completions, and content lives in a messages field. The request structure, streaming events, and tool-call formatting differ enough between the two that pointing Codex directly at DeepSeek’s endpoint almost never works. You’ll either get an empty model list or a hard 404 the moment you try to send a message.
Tools like CC Switch solve this by sitting in the middle. Codex keeps talking to a local address (typically 127.0.0.1:15721) as if it were a normal Responses API provider. Behind that address, a local translation layer rewrites the request into Chat Completions format, forwards it to DeepSeek, and converts DeepSeek’s response back into something Codex understands. Once you internalize that there’s a translator sitting in the middle of this chain, every error below becomes a lot easier to place.
Error 1: expected value at line 1 column 1 — Your curl Command Is Wrong, Not the Proxy
Before blaming the service, check the terminal. On Windows, if you paste a bash-style curl command straight into cmd.exe — single quotes wrapping the JSON, $VAR for environment variables — you’ll get something like:
expected value at line 1 column 1
The cause is mundane: cmd.exe doesn’t treat single quotes as a string delimiter, so it sends the quote character literally as part of the payload. The JSON parser reads a stray ' as the first character instead of {, and fails immediately. $DEEPSEEK_API_KEY also won’t expand in cmd — that shell uses %VAR% syntax instead.
The correct cmd.exe version wraps the JSON in double quotes and escapes the inner ones:
curl http://127.0.0.1:15721/v1/responses ^
-H "Content-Type: application/json" ^
-H "Authorization: Bearer YOUR_KEY" ^
-d "{\"model\":\"deepseek-v4-pro\",\"input\":[{\"role\":\"user\",\"content\":\"hi\"}],\"stream\":false}"
If that’s too much escaping to deal with, switch to PowerShell instead — it accepts single-quoted JSON and $env:VAR syntax, which matches most tutorials you’ll find online. This is a basic shell issue, not a deep one, but it trips up a surprising number of people early in the process — worth ruling out first before assuming the proxy is broken.
Error 2: error sending request — The Local Proxy Can’t Reach DeepSeek
Once the curl syntax is fixed, if you’re seeing something like:
cause: 转发失败: 上游请求发送失败: error sending request
the request reached the local CC Switch proxy fine, and the proxy tried to forward it outward — but the outbound connection to DeepSeek’s servers itself failed. The first useful check is to bypass the proxy entirely and hit DeepSeek’s official endpoint directly:
curl https://api.deepseek.com/v1/models -H "Authorization: Bearer YOUR_KEY"
If that also fails, the problem is network-level or key-related. If it succeeds and returns a model list, both your network and your API key are fine — the failure is isolated to the CC Switch process’s own network context.
This is the detail that’s easy to miss: a terminal window’s network state and a background process’s network state are not the same thing. If you’re running a VPN or proxy tool and toggled it mid-session, a fresh curl call picks up your current state, but CC Switch was launched earlier and may still be holding onto whatever proxy environment variables were set when it started. Check for leftovers:
echo %HTTP_PROXY%
echo %HTTPS_PROXY%
echo %ALL_PROXY%
If these were configured before — especially if you set up a .env file for Codex without also setting NO_PROXY — you can end up in a state where things only work with the proxy on, or only with it off, depending on what the background process inherited. The most reliable fix is to fully quit and relaunch the CC Switch process so it picks up your current network configuration, rather than assuming it will detect the change on its own.
Error 3: upstream_status: HTTP 404 — DeepSeek Responded, But to the Wrong Path
Once the network path is confirmed working, a response like this means the request reached DeepSeek’s servers and got a clear answer back:
upstream_status: HTTP 404; cause: 上游错误 (404)
This isn’t a network problem anymore — it’s the same protocol mismatch from the introduction, just showing up in a different place. CC Switch isn’t recognizing this provider as one that needs format conversion, so it’s passing the Responses-style request straight through to DeepSeek, which has no /responses endpoint to receive it.
Check the provider’s configuration for a setting like “API Format” or “Needs Local Routing.” If this provider was added manually, it’s easy to miss checking the box for “OpenAI Chat Completions (requires routing).” Rather than fixing the manual config field by field, it’s usually faster to delete the manual entry and switch to the tool’s built-in DeepSeek preset — presets are pre-configured specifically to handle this protocol gap, which removes most of the manual configuration risk. This is the part of the whole process worth internalizing: when a third-party model won’t connect to an agent tool, check for an official or community-maintained preset before hand-rolling the config yourself.
Error 4: Empty input messages — You’re Almost There, Your Test Payload Is Wrong
After switching to the built-in preset, a response like this is actually good news:
upstream_status: HTTP 400; cause: Empty input messages
The request made it through the translation layer and reached DeepSeek successfully — DeepSeek processed it fine, it just received an empty conversation. Tracing this back, the usual culprit is the test curl command itself using the wrong field name.
The /responses endpoint expects the Responses API format, where content lives in an input field. It’s easy to default to the Chat Completions habit of using a messages field instead. CC Switch parses the request as Responses format, finds no input, and forwards an empty array to DeepSeek — which correctly reports that the messages are empty. This isn’t a bug; it’s a test script using the wrong protocol.
The corrected test:
curl http://127.0.0.1:15721/v1/responses ^
-H "Content-Type: application/json" ^
-H "Authorization: Bearer YOUR_KEY" ^
-d "{\"model\":\"deepseek-v4-pro\",\"input\":[{\"role\":\"user\",\"content\":\"hi\"}],\"stream\":false}"
If this returns a proper response with actual content, the full chain — Codex → CC Switch → DeepSeek — is working end to end. At that point it’s worth testing directly inside Codex itself rather than continuing to test via curl, since Codex’s own outgoing requests are already correctly formatted as Responses API calls and won’t run into the field-naming mistake a hand-written test script can make.
Responses API vs. Chat Completions: The Core Difference
| OpenAI Responses API (Codex default) | OpenAI Chat Completions (DeepSeek native) | |
|---|---|---|
| Endpoint | /responses |
/chat/completions |
| Content field | input |
messages |
| Typical failure mode | Wrong field name, missing translation | 404 if hit with a Responses-style request |
| Role in this setup | Target format the proxy must produce | Format the proxy must convert to |
Once this table clicks, all four errors above turn out to be the same root cause showing up at different points in the chain. The curl syntax error happens while you’re building the request yourself. The connection failure happens while the proxy forwards it upstream. The 404 happens because the protocol translation step wasn’t triggered. The empty-messages error happens because your own test request used the wrong field for that layer. When debugging any cross-protocol bridging tool, it’s more useful to first figure out which link in the chain you’re stuck on than to jump straight to suspecting a specific component is broken.
A Quick Word on API Key Hygiene
It’s tempting to paste a real API key straight into a terminal command while troubleshooting and share it for help. That habit carries real risk — chat logs, screenshots, and clipboard history are all places a key can leak from, and once it’s out, it can be used to rack up charges on your account. The safer habit is to use a placeholder in anything you’re sharing, and keep the real key local to your own environment or referenced through an environment variable rather than typed directly into a command. If a key has ever shown up somewhere it shouldn’t have, revoking and regenerating it in the provider’s dashboard is a lot cheaper than dealing with the aftermath of a leak.
Quick Reference Checklist
-
[ ] Confirm which shell you’re in (cmd vs. PowerShell) — curl syntax differs between them -
[ ] curl DeepSeek’s official endpoint directly to rule out network and key issues -
[ ] Check HTTP_PROXY/HTTPS_PROXYenvironment variables for leftover or mismatched proxy state -
[ ] Fully restart the local proxy/router process instead of just toggling settings -
[ ] Use the tool’s built-in DeepSeek preset instead of manual config to avoid missing the routing flag -
[ ] Match your test payload’s field name ( input) to the/responsesendpoint, notmessages -
[ ] Once the chain works via curl, test inside Codex itself as the real-world check -
[ ] Regenerate any API key that’s been pasted into a terminal, chat log, or shared screenshot
TL;DR
Codex speaks Responses API by default; DeepSeek’s official API only speaks Chat Completions. Every error in this chain maps to one of three stages: building the request yourself, the proxy forwarding it upstream, or the proxy translating between the two formats. Keep that three-stage mental model handy and most new errors in this setup become quick to place.
FAQ
Local proxy tests pass, but Codex itself still won’t connect. What’s wrong?
Check whether Codex’s config file actually points its base URL at the local proxy address, and whether routing is toggled on. A passing curl test doesn’t guarantee Codex’s own config is pointed at the right place.
Why does curl work against DeepSeek’s official API directly, but fail through the local proxy?
That means your network and API key are both fine — the issue is isolated to the proxy process’s own network context, often leftover proxy environment variables. Restarting the proxy process usually resolves it.
What’s the actual difference between a 404 and a 400 here?
A 404 usually means the request never hit the right protocol path at all. A 400 means the path and protocol were correct, but something in the request body itself was wrong — like a missing or mislabeled field.
Do I really need to use the built-in preset, or can I configure DeepSeek manually?
Manual configuration can work, but you’re responsible for getting every protocol detail right yourself, including whether routing conversion is enabled and which field names apply. Presets are pre-tuned for exactly these details and cut out most of the manual error surface.
Should I test with cmd or PowerShell on Windows?
Either works, but don’t copy commands between them without adjusting syntax. PowerShell accepts single-quoted JSON and $env: variables, closer to what most tutorials show. cmd requires double quotes with escaped inner quotes, so commands copied from tutorials usually need rewriting first.
Can I tell from the error message alone which stage of the chain failed?
Mostly, yes. An error sending request type message points to a connection-layer failure before any response was received. An upstream_status field appearing in the error means the request reached the upstream server and got back a real HTTP status — so the problem is in how the server interpreted the request, not in connectivity.
