[KongchangAI]
· 3 min read· 1,993 words

MiniMax M3.1 Flash Migration in Practice: Fixing Error 2013 and Tuning Thinking Mode

MiniMax M3.1 Flash Migration in Practice: Fixing Error 2013 and Tuning Thinking Mode

Hands-on migration from retiring M2.x to M3.1 Flash: three failure types, cost spikes, and Agent integration tips.

MiniMax M2.5/M2.7 retire on November 18, forcing a migration to M3.1 Flash that is not smooth. Testing revealed three problem classes: Chat Completions with thinking disabled returns HTTP 400 (error 2013) because the model always thinks and only accepts adaptive; other "disable thinking" attempts fail silently, returning 200 while still reasoning, detectable only via reasoning_tokens; and omitting effort defaults to max — the same bug-fix task used 6,364 reasoning tokens and 56 seconds, roughly 10x the low setting's cost. The article also covers Claude Code, Codex CLI, and OpenCode setup (plus an OpenCode effort-variant workaround), notes that cache_control is unsupported and image URL fetch failures also trigger 2013 (use base64 instead), and lists unverified boundaries. The key lesson: 200 does not mean your config took effect — set effort explicitly, check reasoning_tokens, and re-run evals.

Title

MiniMax M3.1 Flash Migration in Practice: Fixing Error 2013 and Tuning Thinking Mode

Meta Description

A practical guide to migrating from MiniMax M2.7 to M3.1 Flash: diagnosing and fixing error 2013 (requires adaptive thinking), measuring the cost gap between the default max effort and low (~10x), and covering silent failures and configuration tips for Claude Code, Codex CLI, and OpenCode integrations.

Article Content

MiniMax M2.5 and M2.7 will be officially retired on November 18, forcing many teams to migrate to M3.1 Flash. The migration is not smooth: when we sent M2.x-style requests to M3.1 Flash, we ran into three classes of problems — one explicit 400 error, several silent failures, and a cost spike caused by the default thinking effort. Based on measured data, this article breaks down the causes, the fixes, and the pitfalls in Agent integrations.

Overview of MiniMax M3.1 Flash migration issues

Why You Need to Pay Attention to the Migration Now

MiniMax has announced that M2.5 and M2.7 (including the -highspeed variants) will be retired on November 18. Since October 19, both series have been closed to new users. According to MiniMax's official model page, requests naming these two models under the M Plan and Token PlanAd will actually be served by M3.1 Flash under the old names; pay-as-you-go calls will stop entirely after the retirement date.

This means that if your logs still say M2.7, the model behind them may already have changed: context went from 204,800 to 1M, top_p from 0.9 to 0.95, and thinking mode runs at max by default. The official guidance explicitly recommends re-running your evals — this is not optional; it's a required migration step.

Error 2013: Reproducing and Fixing "requires adaptive thinking"

The most direct error comes from the Chat Completions API. When we sent thinking: {"type": "disabled"}, it returned HTTP 400:

"invalid params, model \"MiniMax-M3.1-Flash\" requires adaptive thinking; 
thinking.type=\"disabled\" (including reasoning.effort=none) is not allowed (2013)"

The root cause is a difference in model capabilities. MiniMax's Messages API documentation states that this model "always thinks," and if thinking.type is sent at all, it must be adaptive. Code written for M3 runs into trouble because M3 can turn thinking off. Some frameworks categorize the model as a non-reasoning model and send "thinking off" by default, so every call fails — both the kodus-ai and 9router-go projects reported the same issue.

The fix is straightforward: either remove the thinking field or send {"type": "adaptive"}. If you want more speed, lower the effort rather than disabling thinking:

resp = client.chat.completions.create(
    model="minimax-m3.1-flash",
    reasoning_effort="low",   # low | medium | high | xhigh | max; omitted = max
    max_tokens=32768,         # thinking tokens count toward this limit
    messages=[{"role": "user", "content": "..."}],
)

Adaptive thinking is a reasoning control mode introduced by MiniMax in the M3 series: the model decides for itself when to reason and how deeply, and the caller no longer has a switch to "turn thinking off." This contrasts with the explicit switch used in earlier M2.x (thinking.type: enabled/disabled), where developers could skip the reasoning phase entirely in exchange for latency and cost. M3.1 Flash is an "always thinks" model, and thinking.type only accepts adaptive or being omitted, which means the control granularity shifts from "on/off" to "how much effort." This change follows the same trend as Anthropic's extended thinking on Claude 3.7+ and OpenAI's reasoning effort tiers: vendors are increasingly treating reasoning as an inherent model capability rather than an optional plugin, exposing only budget adjustment at the API level. Understanding this is critical — any code path that tries to "completely turn off thinking" during migration will fail; the right approach is to switch to an effort parameter like reasoning_effort and factor thinking tokens into your max_tokens and cost budgeting.

reasoning_tokens is the sub-field in the response usage object that counts internal reasoning consumption. It is metered separately from visible output tokens but is usually billed at the output price. Because reasoning content is not returned in the body by default, looking only at content cannot tell you whether the model really "didn't think" — this is exactly the root of silent failures. We recommend parsing usage.completion_tokens_details.reasoning_tokens (or the equivalent field) uniformly in the integration layer and instrumenting every call; alert when this value is abnormally high to catch issues like effort not being passed through or configuration being overridden early. In Agent loops, you should also add reasoning_tokens into per-step cost, otherwise it's easy to underestimate the overhead of the entire workflow.

Silent Failures: Returning 200 but Behaving Unexpectedly

More insidious than the 400 are those requests that return 200 but don't "obey." We tested various ways of "turning off thinking," with the following results:

Request methodActual behavior
Messages + thinking disabledStill thinks: short puzzle consumes 469–622 tokens
Chat + reasoning_effort noneStill thinks: 265–372 tokens
Chat + reasoning_effort minimalStill thinks
Omit effortRuns at max effort
max_tokens set to 64finish_reason is length, response truncated
cache_control blocksNot supported; caching is automatic
service_tierNot supported; no Priority tier

Only Chat Completions with thinking: {"type": "disabled"} produces a 400; all other attempts to "turn off thinking" fail silently. For migrating teams, this means you cannot rely on "no error" to judge whether the configuration took effect — you must check reasoning_tokens in the response.

Cost Measurements: Default max Effort Is 7x More Expensive

The effort setting directly determines your post-migration bill. We benchmarked a task of fixing a Python function containing two bugs, checked against 215 hidden tests, running each setting three times:

SettingAvg. reasoning tokensAvg. latencyCost per fix
Omit effort (max)6,36456 s$0.0045
effort = low5919.5 s$0.0006

All runs passed the tests. At AIHubMix pricing ($0.165 input, $0.66 output, $0.0165 cache read per 1M tokens), thinking tokens account for 95% of output under the default setting (6,364 / 6,673). In other words, the thinking cost of a small bug fix is more than 10x that of the low-effort setting, and latency is nearly 6x. If the Agent thinks before every tool call, this gap gets amplified across the entire workflow.

Key Points for Agent and Coding Tool Integrations

In Agent scenarios, M3.1 Flash has several behavioral traits to watch for. First, it reasons before every tool call — even at the low setting, short tool steps take 2–7 seconds. Second, it follows instructions strictly — early testers described it as "blazing fast, but needs clear and specific instructions, otherwise it's too lazy," so explicit stopping conditions and verification steps are critical.

On protocol support, we tested three mainstream tools:

ToolProtocolAvailable via AIHubMixEffort field
Claude CodeAnthropic MessagesYesoutput_config.effort
Codex CLIOpenAI ResponsesYesreasoning.effort
OpenCodeOpenAI-compatibleYesreasoning_effort

OpenCode has a known issue (issue #54801, reproduced on v2.0.27): it cannot resolve effort variants for this model. The workaround is to declare five variants in opencode.json, each setting reasoning_effort, and be careful not to add none.

A rough Claude Code configuration looks like this:

export ANTHROPIC_BASE_URL="https://aihubmix.com"
export ANTHROPIC_AUTH_TOKEN="$AIHUBMIX_API_KEY"
export ANTHROPIC_MODEL="minimax-m3.1-flash"
export ANTHROPIC_DEFAULT_HAIKU_MODEL="minimax-m3.1-flash"

We recommend a ~15-minute smoke test: give the Agent a temporary directory with a known bug and failing tests, and ask it to "run the tests first, fix the bug, then run the tests again and show the output." The pass criteria are: tests were run both before and after the fix, the final run is green, the interaction spans multiple turns, and there are no 400s. In the usage logs, minimax-m3.1-flash requests should show reasoning tokens; if each turn takes close to a minute, the effort setting isn't reaching the model.

Smoke testing is a low-cost verification method in migration scenarios: use the smallest possible case that embodies the full end-to-end path to quickly confirm that configuration, authentication, protocol adaptation, and key behaviors are as expected, without aiming for coverage. For this migration, the smoke case needs to cover three things at once — whether the protocol connects (no 400), whether effort is actually passed through (reasonable reasoning_tokens in the logs), and whether the Agent can complete a multi-turn tool-calling loop (tests go green). It matters because most of the failures in this migration are silent: requests returning 200 may be running at max effort, and billing and latency problems only surface once production traffic amplifies them. We recommend adding the smoke script to CI, running it automatically when the model version, base URL, or environment variables change, and locking in reasoning_tokens and end-to-end latency as two metrics in the output to form a comparable baseline.

Other Details to Watch

Context window: 1,000,000 tokens on the MiniMax API, but the MiniMax Code client defaults to 512K "to balance experience and cost"; the API itself has no window parameter.

Caching: cache_control is not supported on M3.1 Flash (or M3). M2.7 used to bill explicit cache writes at $0.375 per 1M tokens. Every request we sent (including the first) had about 175–195 prompt tokens coming from cache, which appears to be a fixed preamble on MiniMax's side.

Error 2013 on image uploads: the same error code can also come from a failed image URL fetch. Image URLs on upload.wikimedia.org returned 400, while base64 images or URLs from other hosts returned 200. MiniMax hasn't documented this scenario; our interpretation is that the upstream can't fetch the image. We recommend using the data:image/png;base64,… format uniformly, and reading the full error message before searching the logs.

Boundaries We Couldn't Verify

To be honest, there are a few questions we couldn't answer definitively: whether Claude Code's effort setting is actually passed to non-Claude models as output_config.effort — the docs don't say, and if it isn't passed, the model runs at max; forced tool calls (tool_choice required/any) are accepted by AIHubMix and the tools are indeed called, but MiniMax only documents auto, so this behavior can't be relied on; the impact of stripping thinking blocks on long tool loops — we only tested a single short round trip; and what will happen to AIHubMix's own minimax-m2.7 routing after November 18 — there's no official word. All timing data comes from three runs per setting; small differences should be treated as noise.

The core lesson from migrating to M3.1 Flash: don't assume "returns 200" means the configuration took effect. Set effort explicitly, check reasoning_tokens, and re-run your evals — that's how you avoid billing and latency surprises.

One-line Summary

A hands-on look at migrating from retiring M2.x to M3.1 Flash: three classes of failures, cost spikes, and Agent integration tips.

Paragraph Summary

MiniMax M2.5/M2.7 will be retired on November 18, forcing teams to migrate to M3.1 Flash — and the migration isn't smooth. Based on hands-on testing, the author breaks down three classes of problems: sending thinking disabled via Chat Completions returns HTTP 400 (error code 2013) because the model always thinks and only accepts adaptive; all other "turn off thinking" approaches fail silently, returning 200 while still reasoning, so you can only tell by checking reasoning_tokens; and when effort is omitted, it runs at max by default — the same bug-fix task consumed 6,364 reasoning tokens and 56 seconds, about 10x the cost of the low setting. The article also covers how to connect Claude Code, Codex CLI, and OpenCode, plus a workaround for OpenCode's effort variants; notes that cache_control isn't supported and that failed image URL fetches also trigger 2013, recommending base64 instead; and lists several unverified boundaries. The core takeaway: returning 200 doesn't mean the configuration took effect — you must set effort explicitly, check reasoning_tokens, and re-run your evals.

#MiniMax M3.1 Flash#MiniMax migration#error 2013#adaptive thinking#reasoning_effort#Claude Code#Codex CLI#OpenCode
Share:

Related articles