On this page
Calling the official DeepSeek API in thinking mode with tool calling enabled, a bare 400 often points to missing history rather than a bad tool schema. DeepSeek’s Thinking Mode guide is clear: when tools is on the request, reasoning_content from previous turns must be fully returned on every subsequent request. Drop it—intentionally or through a store, proxy, or serializer that only keeps content—and the API rejects the call. Everything below follows that guide as of October 26, 2026 (Beijing time). For reference only; this failure has not been reproduced on this site, and a fix has not been tested here. Feedback from production hits can go through the site-owner contact link in the footer.
The symptom: 400 with tools in thinking mode
Thinking mode is on by default for DeepSeek’s Chat Completions path. The model first emits a chain of thought, then the final answer. Those two pieces arrive as sibling fields on the assistant message: reasoning_content and content.
When you also pass a tools array, DeepSeek expects the conversation history to keep that chain of thought. The docs say that if your code does not correctly pass reasoning_content back, the API returns a 400 error. That is the failure this note is about—not auth failures, not rate limits, and not every other 400 you might see.
The rule: pass back all historical reasoning_content
For any request that carries tools:
- Pass back the
reasoning_contentof all previous turns. - Those values are concatenated into the model context.
- You must keep doing this on every subsequent request, including turns where the model did not issue a tool call.
DeepSeek’s sample pattern is the safest default: append the whole assistant message object the SDK returned.
messages.append(response.choices[0].message)That object already holds content, reasoning_content, and tool_calls. The explicit equivalent is:
messages.append({
"role": "assistant",
"content": response.choices[0].message.content,
"reasoning_content": response.choices[0].message.reasoning_content,
"tool_calls": response.choices[0].message.tool_calls,
})If your own history builder rebuilds assistant messages from only role + content, you will silently drop reasoning_content—and the next tools request can come back 400.
When the request does not carry tools
Without tools, the rule flips:
- You do not need to pass
reasoning_contentback. - Even if you do send it, the API ignores it and does not concatenate it into context.
So a multi-turn chat that never attaches tools can keep only content and still behave as the Multi-turn Conversation section describes. The hard requirement starts the moment tools is present on the request.
Where reasoning_content usually gets dropped
Visitor-facing places that commonly strip the field:
- Client message stores that persist only
roleandcontent, then rebuild history for the next call. - Proxies and gateways that whitelist OpenAI-shaped fields and discard unknown keys such as
reasoning_content. - History databases or ORMs whose schema has a
contentcolumn but no column for chain-of-thought text. - Manual JSON serializers that copy
tool_callsbut forget the siblingreasoning_contenton the same assistant turn.
If your stack sits between the SDK response and the next request, check that the field survives the round trip—especially after a tool result is appended and you fire the follow-up completion.
What this is not
A few boundaries so this note stays useful:
- Not every HTTP 400 from DeepSeek is a missing
reasoning_content. Invalid payloads, auth problems, and other validation errors also return 400. Treat this guide as one documented cause when thinking mode andtoolsare both in play. - Not the DeepSeek Harness install path. Installing or wiring a coding harness is a separate topic—see DeepSeek Harness Install Guide: Windows, Linux, CLI, Plugins. This page is only about the API history rule for thinking mode plus
tools. - Official DeepSeek API scope. The wording above follows DeepSeek’s own Thinking Mode docs for the official API. Third-party relays may behave differently; check their docs separately.
Related reading
Nearby DeepSeek and harness context on this site:
