Skip to content

DeepSeek V4-Flash native Responses route: 400 missing field queries on replayed web_search_call #930

Closed

Description

@Hzzz7

``markdown

Client or integration

Codex App

Area

Proxy and routing

Summary

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

  1. 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").
  2. In the Codex App, run a turn that performs a web search, so a web_search_call history item is recorded.
  3. Send any follow-up message in the same conversation.
  4. 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:

{"type":"web_search_call","id":"ws_x","status":"completed","action":{"type":"search","query":"test"}}

→ 400 missing field 'queries'.

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.

Activity

  1. github-actions commented on Aug 3, 2026

    @github-actions
    Contributor

    Automated translation bookkeeping — detected language: unknown.

  2. github-actions commented on Aug 3, 2026

    @github-actions
    Contributor

    Issue reopened

    The report now contains the information required by the automated check. Thanks for updating it.

  3. added
    bugSomething isn't working
    proxyHTTP proxy, routing, reverse-proxy / management auth
    on Aug 3, 2026
  4. added a commit that references this issue on Aug 3, 2026
    8a72834
  5. added a commit that references this issue on Aug 3, 2026
    6a7351b
  6. lidge-jun commented on Aug 3, 2026

    @lidge-jun
    Owner

    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 missing queries 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.

  7. added 3 commits that reference this issue on Sep 17, 2026
    101dac6
    851b092
    22ec145
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingproxyHTTP proxy, routing, reverse-proxy / management authtoolstool_calls, MCP, web-search / sidecar tools

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions