If a DeepSeek tool loop fails with HTTP 400 on the request right after its first tool call, DeepSeek's docs point to one dropped field: reasoning_content. That's the loud part of moving to DeepSeek V4.1 Flash 1017. The quiet part happened on October 17, 2026, when DeepSeek swapped the checkpoint behind deepseek-flash without changing the name or the price. Many apps migrated that afternoon without anyone deciding to.
This post is the engineering side of the move: reproduce and fix the 400, detect the swap from the response itself, see what peak hours and the effort setting do to the bill, and wire Claude Code, Codex, and DeepSeek Harness to the new checkpoint. On AIHubMix it has its own ID, deepseek-v4.1-flash-1017, so the switch happens when you change the model string, not when DeepSeek ships.
TL;DR
- With
toolsin the request, DeepSeek requires thereasoning_contentof every earlier assistant turn. Drop it and DeepSeek's API returns 400. Append the whole assistant message to your history. -
deepseek-flash,deepseek-v4-flash, anddeepseek-v4-flash-vision-expon DeepSeek's API all run 1017 now, and there is no pinned name for the September checkpoint. Log the response'smodelfield and rerun your evals. - Weekday peak hours (01:00–04:00 and 06:00–10:00 UTC) cost twice the off-peak rate. A sample agent session comes to $0.118 at peak and $0.059 off-peak.
- Keep effort at
high. DeepSeek's own paper saysmaxlengthens agent runs 1.6–1.8× for marginal gains. - Through AIHubMix, Chat Completions, Anthropic Messages, and the Responses API all returned 200 in a one-run test on October 19.
Prerequisites
- An AIHubMix API key in
AIHUBMIX_API_KEY. - Model ID
deepseek-v4.1-flash-1017. OpenAI-format clients use the base URLhttps://aihubmix.com/v1; Claude Code useshttps://aihubmix.com. - For the smoke test at the end: git, Python with pytest, and one of Claude Code, Codex, or DeepSeek Harness.
What AIHubMix tested
AIHubMix sent a short set of requests to deepseek-v4.1-flash-1017 on October 19, 2026, at 03:02 UTC. Each check ran once, so read every row as "worked once", not as a guarantee.
| Check | Endpoint | Result |
|---|---|---|
| Effort low, high, max | Chat Completions | 200 for all three |
| Tool turn 2 without reasoning_content | Chat Completions | 200, normal answer |
| Two-turn tool call | Anthropic Messages | 200 on both turns |
| No effort setting | Anthropic Messages | No thinking block |
| output_config.effort set to low | Anthropic Messages | Thinking block returned |
| reasoning.effort set to low | Responses | 200, reasoning + message |
Every response carried "model": "deepseek-v4-1-flash-261017", the 1017 checkpoint.
Failure 1: HTTP 400 on the request after a tool call
Symptom. The request that sends the tool result back fails with this message, as reported in a GitHub issue against opencodex for V4.1 Flash on October 15:
[invalid_request_error] The `reasoning_content` in the thinking mode must be passed back to the API.
The same text shows up in earlier reports against opencode, LangChain, and claude-code-router for V4 Pro and V4 Flash.
Cause. DeepSeek's thinking mode guide says that when a request includes tools, the reasoning_content of every earlier assistant turn must be sent back, "even for turns where the model did not perform a tool call". If it isn't, "the API will return a 400 error". Without tools, sending it back is optional and ignored. Clients trip on this because their message serialiser keeps content and tool_calls and drops the extra field.
Reproduce. Turn two of a tool loop, with the assistant message stripped of reasoning_content:
curl -s https://aihubmix.com/v1/chat/completions \
-H "Authorization: Bearer $AIHUBMIX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "deepseek-v4.1-flash-1017",
"tools": [{"type": "function", "function": {"name": "get_weather",
"parameters": {"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]}}}],
"messages": [
{"role": "user", "content": "What is the temperature in Hangzhou? Use the tool."},
{"role": "assistant", "content": null, "tool_calls": [{"id": "call_00_example", "type": "function",
"function": {"name": "get_weather", "arguments": "{\"city\": \"Hangzhou\"}"}}]},
{"role": "tool", "tool_call_id": "call_00_example", "content": "{\"celsius\": 18}"}
]
}'
On DeepSeek's own API, this is the shape that returns the 400 in the public reports. Through AIHubMix, the same shape returned HTTP 200 and a normal answer in the October 19 run. That was one request, and the response doesn't show which upstream channel served it, so treat it as an observation, not a contract.
Fix. Keep the field, whichever route you use:
msg = resp.choices[0].message
messages.append(msg) # carries content, reasoning_content, and tool_calls over
- In your own code, append the whole assistant message, not a hand-built copy of it.
- In frameworks, upgrade: opencode fixed the round trip in later releases, and opencodex merged its fix on October 16.
- As a last resort, set
{"thinking": {"type": "disabled"}}for tool loops. That avoids the error but gives up the reasoning that makes the model good at agent work.
Failure 2: no error, different model
DeepSeek's changelog for October 17: "The API calling method and pricing remain unchanged — simply use deepseek-flash to access the latest model." There is no pinned name for the September checkpoint, and the two older Flash names run on 1017 too.
Nothing throws, but three things can shift under your tests:
- Output length. 1017 was trained to produce shorter outputs. Parsers, UI layouts, and prompts that expected the September model's long explanations may get less text. DeepSeek hasn't put a number on how much shorter.
-
Evaluation baselines. Scores and costs recorded on the September checkpoint no longer describe what
deepseek-flashreturns. - Behaviour. DeepSeek retrained 1017 for end-to-end project work, so agents may take different paths to the same result.
Detect it. The response tells you which checkpoint answered. Through AIHubMix, every response in the test carried "model": "deepseek-v4-1-flash-261017". Store that field and the date with every evaluation run, rerun your regression set now, and an unannounced swap shows up the day it happens.
Failure 3: the bill doubles at weekday peak
DeepSeek charges full price 01:00–04:00 and 06:00–10:00 UTC on weekdays, and half price at every other hour, all weekend, and on Chinese public holidays. AIHubMix uses the same windows and prices each request at the time it was submitted, so a long streaming request that starts off-peak stays off-peak.
| Item | Peak | Off-peak |
|---|---|---|
| Input, cache miss | $0.3098 | $0.155 |
| Input, cache hit | $0.0062 | $0.0031 |
| Output | $1.2392 | $0.62 |
AIHubMix list prices per 1M tokens for deepseek-v4.1-flash-1017. A limited-time 30% discount is running on top.
A worked example, under stated assumptions: one agent session of 40 calls, 1.2M input tokens with 90% cache hits, and 60K output tokens.
- Peak: 0.12M × $0.3098 + 1.08M × $0.0062 + 0.06M × $1.2392 = $0.118
- Off-peak: the same tokens at half the rate = $0.059
Three levers move that number:
- Schedule. Moving batch runs off-peak is the single biggest saving.
- Cache. Hits are 50 times cheaper than misses. Agents resend the same system prompt, tool definitions, and history on every call; keep that prefix stable and put anything that changes per call at the end.
-
Thinking. It's on by default, and reasoning tokens count toward both the bill and
max_tokens.
One date to put in the calendar: DeepSeek opened its new Search and Fetch APIs on October 17 at $0.75 per 1,000 successful calls each. Server-side calls made through DeepSeek Harness, Claude Code, or Codex on DeepSeek's API are free until October 31, 2026, 16:00 UTC. After that, an agent that searches on every turn adds a per-call cost on top of tokens.
Failure 4: settings that cost more than they return
Effort. The API offers low, high (default), and max. DeepSeek's V4.1 Flash paper maps them to internal effort values of 50, 75, and 100, and reports that the step to max "lengthens agent trajectories by 1.6–1.8× for only marginal improvements". DeepSeek's own Claude Code setup guide still sets CLAUDE_CODE_EFFORT_LEVEL=max. For everyday agent work, high is the better default.
Other effort names get folded in: minimal becomes low, while medium and xhigh both become high. A tool that offers five levels effectively gives you two or three. In the October 19 test, AIHubMix accepted low, high, and max on Chat Completions.
max_tokens. The model card recommends at least 256K for long agent runs, because thinking shares the output budget. With a small cap, a hard step can spend the whole budget thinking. Alert on finish_reason: "length".
Sampling. In thinking mode, temperature, presence_penalty, and frequency_penalty are accepted without error and have no effect. top_p is clamped to 0.95–1.0. A pipeline that relied on low temperature for deterministic output no longer gets it.
Before you give it shell access
1017 was trained with reinforcement learning on whole projects, so it tends to keep building until the job looks done. Its answers are also shorter, which means less narration of what it changed.
- Review diffs and command logs, not the model's summary of them.
- Run it in a sandbox with an allowlist of commands, and require approval for anything destructive: deletes, force pushes, migrations, outbound network calls.
DeepSeek itself flags the Flash line's strength on security tasks; the September checkpoint scored 88.1 on CyberGym in DeepSeek's own table. That's useful for defensive work, and another reason to scope its permissions tightly.
Wiring the coding tools
AIHubMix serves deepseek-v4.1-flash-1017 on all three protocols these tools need: Claude Code speaks Anthropic Messages, Codex the Responses API, DeepSeek Harness Chat Completions.
Claude Code. Point it at AIHubMix as in the Claude Code guide and set the model:
export ANTHROPIC_BASE_URL="https://aihubmix.com"
export ANTHROPIC_AUTH_TOKEN="$AIHUBMIX_API_KEY"
export ANTHROPIC_MODEL="deepseek-v4.1-flash-1017"
export ANTHROPIC_DEFAULT_HAIKU_MODEL="deepseek-v4.1-flash-1017"
export CLAUDE_CODE_SUBAGENT_MODEL="deepseek-v4.1-flash-1017"
export CLAUDE_CODE_EFFORT_LEVEL="high"
-
Keep an effort level set. In the test, a Messages request with no effort setting came back without a thinking block, while one with
output_config.effortreturned thinking. Check the request logs to confirm 1017 is reasoning. -
The
[1m]suffix. DeepSeek's guide adds it to the model name for its own endpoint; it wasn't tested through AIHubMix. - Known issue. Through some routers, Claude Code has dropped thinking content and hit the 400 above (claude-code-router issue 1378). The two-turn tool test through AIHubMix's Messages endpoint didn't hit it.
Codex. Follow the Codex CLI guide: an aihubmix provider with base_url = "https://aihubmix.com/v1" and wire_api = "responses", and model = "deepseek-v4.1-flash-1017". To pick it from /model, add it to a model_catalog_json file with context_window set to 1,000,000.
- The guide's catalog script offers
low,medium, andhigh. Under DeepSeek's mapping,mediumandhighboth land on DeepSeek'shigh, so you get two real levels. - Newer Codex versions discard the whole catalog if a single required field is missing. The guide's script avoids that.
DeepSeek Harness. DeepSeek says 1017 works best with Harness 0.2.1-rc.1 or later. Add AIHubMix as an OpenAI-compatible provider following the DeepSeek Harness guide, then add deepseek-v4.1-flash-1017 as a model. The guide was written against an earlier Harness release, so check field names if the UI has changed.
A 15-minute smoke test
Create a tiny repo with one failing test:
mkdir flash-smoke && cd flash-smoke && git init -q
printf 'def mean(xs):\n return sum(xs) / len(xs)\n' > stats.py
printf 'from stats import mean\n\ndef test_mean():\n assert mean([1, 2, 3]) == 2\n\ndef test_empty():\n assert mean([]) == 0\n' > test_stats.py
Start your tool in that folder and ask: "Run pytest, fix the failing test by changing stats.py only, then run pytest again." It passes if:
- the agent makes at least two tool calls (run the tests, edit the file) with no 400;
- both tests pass at the end;
- the AIHubMix request log shows
deepseek-v4.1-flash-1017, and the session cost is a few cents at most.
What this doesn't tell you
- The 200 on the stripped tool turn. One request, upstream channel not visible. DeepSeek's rule still stands; send the field.
-
Effort cost. The effort check used a trivial prompt, and its reasoning token counts (68, 39, and 54 for low, high, and max) don't separate the levels. The cost argument for
highrests on DeepSeek's paper, not on this test. -
Context suffix. The
[1m]model-name suffix from DeepSeek's Claude Code guide is untested through AIHubMix. - Harness UI. The AIHubMix Harness guide predates 0.2.1-rc.1.
-
"Shorter outputs". DeepSeek doesn't quantify it. Compare
completion_tokenson your own prompts with what you logged on the September checkpoint.
Keep reading: the DeepSeek V4.1 Flash 1017 series
- Want the benchmark and cost case before touching your integration? The upgrade post compares 1017 with the September checkpoint: DeepSeek V4.1 Flash 1017: Same Price, Shorter Outputs, and AIHubMix vs OpenRouter Pricing
- Wiring Claude Code anyway? See how 1017 compares with the model Claude Code uses for its own subagents: DeepSeek V4.1 Flash 1017 vs Claude Haiku 5.5: Which Cheap Model for Terminal Coding Agents?
- Migrating from V4 Pro rather than the old Flash? This one checks whether you still need Pro at all: DeepSeek V4.1 Flash 1017 vs V4 Pro: Is the Flash Enough Now?
Sources
- Thinking Mode (DeepSeek)
- Change Log (DeepSeek)
- Integrate with AI Tools (DeepSeek)
- DeepSeek V4.1 Flash 1017 on AIHubMix (AIHubMix)
- DeepSeek V4.1 Flash returns reasoning_content 400 after tool calls, issue 7118 (GitHub)
Top comments (0)