You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
DeepSeek V4-Flash native Responses route: 400 missing field queries on replayed web_search_call #930
After a web search in a conversation using deepseek/deepseek-v4-flash (opencodex 2.10.0, DeepSeek native Responses route), every subsequent turn fails with HTTP 400 invalid_request_error from api.deepseek.com:
Failed to deserialize the JSON body into the target type: input: missing field 'queries' at line 1 column N
I expected the replayed web_search_call history to be accepted by DeepSeek's Responses API (or dropped on translated routes) so the conversation can continue.
Reproduction
Start opencodex 2.10.0 (ocx start --port 10100) with the DeepSeek provider and model deepseek/deepseek-v4-flash on the native Responses route (responsesPath: "/responses").
In the Codex App, run a turn that performs a web search, so a web_search_call history item is recorded.
Send any follow-up message in the same conversation.
Every subsequent turn fails with 400 missing field 'queries'.
Minimal repro against the proxy — POST /v1/responses with model: "deepseek/deepseek-v4-flash" and input containing:
Changing the action to {"type":"search","queries":["test"]} → 200.
Version
2.10.0
Operating system
Windows (build 26200, DisplayVersion 25H2)
Provider and model
deepseek / deepseek-v4-flash
Logs or error output
HTTP 400 invalid_request_error from api.deepseek.com:
Failed to deserialize the JSON body into the target type: input: missing field 'queries' at line 1 column N
Screenshots and supporting files
None.
Redacted configuration
Not applicable — provider adapter routing for deepseek/deepseek-v4-flash as shipped in 2.10.0 (modelWireDefaults + responsesPath: "/responses").
Checks
I searched existing issues and documentation.
I removed secrets, tokens, account details, request credentials, and personal data.
Fixed on dev by #932 (6a7351b4d). Your minimal repro pinned it exactly — swapping query for queries and getting a 200 is what made the root cause unambiguous.
What was wrong.webSearchAction() in src/bridge.ts emitted {type:"search", query:"..."} for a one-term search. That matches the Responses schema and is what codex-rs reads for the search cell label, but DeepSeek's native Responses parser makes queries a required field. Because /responses is stateless and replays full history, the item comes back on every subsequent turn — which is why you saw every following turn fail rather than just the search turn.
Two fixes, and the second one only existed because a review caught it. The first change makes new single-query items carry both keys. That alone would have left your existing conversation broken forever: the stored {query:"..."} replays unchanged after upgrading. So backfillWebSearchQueries() now repairs it at the replay boundary in the Responses adapter — a web_search_call whose action has a string query and no queries gains queries: [query] on the way out.
Existing threads recover on their next turn. No need to start a new conversation.
What deliberately did not change. Batched searches still emit only queries, with no singular query. codex-rs renders the plural form as "<first> ..." only when query is absent and queries.len() > 1, so adding it there would collapse that display. There is a test pinning that, and it stands.
One thing worth stating plainly. DeepSeek's published schema leaves action opaque, so the requirement is not documented — your API result is the evidence. A dual-field object was not POSTed live against DeepSeek; the reasoning is that your query-only request failed with missingqueries rather than rejecting query as unknown, and queries-only returned 200, which means both fields deserialize. If you still see a 400 after upgrading, please reopen with the response body — that would mean DeepSeek rejects the extra key, and the fix would need to drop query on that route specifically.
3 regressions added, verified by ablation in both directions.
Activity
github-actions commentedon Aug 3, 2026
Automated translation bookkeeping — detected language: unknown.
github-actions commentedon Aug 3, 2026
Issue reopened
The report now contains the information required by the automated check. Thanks for updating it.
fix(openai-responses): mirror web_search_call query into queries
Merge pull request #932 from lidge-jun/codex/930-websearch-queries
lidge-jun commentedon Aug 3, 2026
Fixed on
devby #932 (6a7351b4d). Your minimal repro pinned it exactly — swappingqueryforqueriesand getting a 200 is what made the root cause unambiguous.What was wrong.
webSearchAction()insrc/bridge.tsemitted{type:"search", query:"..."}for a one-term search. That matches the Responses schema and is what codex-rs reads for the search cell label, but DeepSeek's native Responses parser makesqueriesa required field. Because/responsesis stateless and replays full history, the item comes back on every subsequent turn — which is why you saw every following turn fail rather than just the search turn.Two fixes, and the second one only existed because a review caught it. The first change makes new single-query items carry both keys. That alone would have left your existing conversation broken forever: the stored
{query:"..."}replays unchanged after upgrading. SobackfillWebSearchQueries()now repairs it at the replay boundary in the Responses adapter — aweb_search_callwhose action has a stringqueryand noqueriesgainsqueries: [query]on the way out.Existing threads recover on their next turn. No need to start a new conversation.
What deliberately did not change. Batched searches still emit only
queries, with no singularquery. codex-rs renders the plural form as"<first> ..."only whenqueryis absent andqueries.len() > 1, so adding it there would collapse that display. There is a test pinning that, and it stands.One thing worth stating plainly. DeepSeek's published schema leaves
actionopaque, so the requirement is not documented — your API result is the evidence. A dual-field object was not POSTed live against DeepSeek; the reasoning is that your query-only request failed with missingqueriesrather than rejectingqueryas unknown, and queries-only returned 200, which means both fields deserialize. If you still see a 400 after upgrading, please reopen with the response body — that would mean DeepSeek rejects the extra key, and the fix would need to dropqueryon that route specifically.3 regressions added, verified by ablation in both directions.
fix(responses): always carry query on web_search_call for Console Go
fix(responses): always carry query on web_search_call for Console Go (#…
fix(responses): always carry query on web_search_call for Console Go (l…
fix(web-search): carry queries on a single-query search so strict par…
Merge pull request lidge-jun#932 from lidge-jun/codex/930-websearch-q…
fix(responses): always carry query on web_search_call for Console Go (l…