Claude Code v2.1.167: Agent() spawn fails with "400 thinking options type cannot be disabled when reasoning_effort is set" on DeepSeek Anthropic-compatible endpoint

Status Open
Reported on v2.1.167
Maintainer reply None cached
Activity 14 comments · opened Jun 6, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

Environment

  • Claude Code: v2.1.167 (npm global install)
  • OS: Windows 11 x64
  • API Endpoint: ANTHROPIC_BASE_URL=https://api.deepseek.com/anthropic
  • Main model: ANTHROPIC_MODEL=deepseek-v4-pro (works fine for main conversation)
  • Sub-agent models: ANTHROPIC_DEFAULT_SONNET_MODEL=deepseek-v4-flash, ANTHROPIC_DEFAULT_HAIKU_MODEL=deepseek-v4-flash (set at Windows User env level)

Steps to Reproduce

  1. Configure Claude Code to use DeepSeek's Anthropic-compatible endpoint
  2. ANTHROPIC_BASE_URL=https://api.deepseek.com/anthropic
  3. ANTHROPIC_MODEL=deepseek-v4-pro
  4. Run any Agent spawn: Agent({ model: "sonnet", subagent_type: "general-purpose", ... })
  5. Observe error: API Error: 400 thinking options type cannot be disabled when reasoning_effort is set

Same error occurs with:

  • WebSearch tool
  • WebFetch tool
  • All three Agent model tiers (sonnet/haiku/opus)

What Works

  • Main conversation on deepseek-v4-pro → ✅ perfect
  • All non-subprocess tools (Read, Write, Edit, Bash, Grep, Glob, etc.) → ✅

What We Tested (Direct API Verification)

We ran 11 direct curl tests to DeepSeek's /anthropic/v1/messages endpoint with thinking: {type: "disabled"} combined with various parameters. All returned 200:

| # | model | extra params | Result |
|---|-------|-------------|--------|
| 1 | v4-pro | — | ✅ |
| 2 | v4-pro | tools:[...] | ✅ |
| 3 | v4-pro | tools + system | ✅ |
| 4 | v4-pro | tools + system + tool_choice:{type:"auto"} | ✅ |
| 5 | v4-pro | reasoning_effort:"high" | ✅ |
| 6 | v4-pro | budget_tokens:0 | ✅ |
| 7 | v4-flash | — | ✅ |
| 8 | v4-flash | tools + system | ✅ |
| 9 | claude-sonnet-4-20250514 | Anthropic model ID (mapped to v4-flash by DeepSeek) | ✅ |

This demonstrates that DeepSeek's Anthropic-compatible endpoint fully supports thinking: disabled — the 400 error is specific to Claude Code's Agent subprocess API request path.

Environment Variable Investigation

We tried setting ANTHROPIC_DEFAULT_SONNET/HAIKU_MODEL=deepseek-v4-flash via three different paths:

  1. settings.json env block
  2. Windows User-level registry (permanent)
  3. Post-restart process inheritance

All three correctly set the env vars (confirmed via echo in subprocesses), but Agent spawn still fails with the same 400 — suggesting the Agent subprocess mechanism bypasses these env vars entirely.

Hypothesis

Claude Code's Agent subprocess API request construction differs from the main conversation path. The subprocess may:

  • Send a parameter or header combination not covered by our direct API tests
  • Use a different HTTP endpoint path
  • Use a different SDK code path that triggers the error

Workaround

Direct execution by Team Lead (no Agent spawn). Quality is unaffected — verified with Critic review scoring 9.0/10 on directly-executed page reviews.

Additional Context

This bug was discovered during systematic /lint --system auditing of a production Obsidian knowledge base (~41K files). The Agent system (Writer/Critic/Researcher with state files, memory, and inter-agent cache channels) was fully deployed but had zero usage over 5 days because every spawn attempt failed silently. The knowledge base has comprehensive self-monitoring protocols that detected the anomaly.

What Should Happen?

Environment

  • Claude Code: v2.1.167 (npm global install)
  • OS: Windows 11 x64
  • API Endpoint: ANTHROPIC_BASE_URL=https://api.deepseek.com/anthropic
  • Main model: ANTHROPIC_MODEL=deepseek-v4-pro (works fine for main conversation)
  • Sub-agent models: ANTHROPIC_DEFAULT_SONNET_MODEL=deepseek-v4-flash, ANTHROPIC_DEFAULT_HAIKU_MODEL=deepseek-v4-flash (set at Windows User env level)

Steps to Reproduce

  1. Configure Claude Code to use DeepSeek's Anthropic-compatible endpoint
  2. ANTHROPIC_BASE_URL=https://api.deepseek.com/anthropic
  3. ANTHROPIC_MODEL=deepseek-v4-pro
  4. Run any Agent spawn: Agent({ model: "sonnet", subagent_type: "general-purpose", ... })
  5. Observe error: API Error: 400 thinking options type cannot be disabled when reasoning_effort is set

Same error occurs with:

  • WebSearch tool
  • WebFetch tool
  • All three Agent model tiers (sonnet/haiku/opus)

What Works

  • Main conversation on deepseek-v4-pro → ✅ perfect
  • All non-subprocess tools (Read, Write, Edit, Bash, Grep, Glob, etc.) → ✅

What We Tested (Direct API Verification)

We ran 11 direct curl tests to DeepSeek's /anthropic/v1/messages endpoint with thinking: {type: "disabled"} combined with various parameters. All returned 200:

| # | model | extra params | Result |
|---|-------|-------------|--------|
| 1 | v4-pro | — | ✅ |
| 2 | v4-pro | tools:[...] | ✅ |
| 3 | v4-pro | tools + system | ✅ |
| 4 | v4-pro | tools + system + tool_choice:{type:"auto"} | ✅ |
| 5 | v4-pro | reasoning_effort:"high" | ✅ |
| 6 | v4-pro | budget_tokens:0 | ✅ |
| 7 | v4-flash | — | ✅ |
| 8 | v4-flash | tools + system | ✅ |
| 9 | claude-sonnet-4-20250514 | Anthropic model ID (mapped to v4-flash by DeepSeek) | ✅ |

This demonstrates that DeepSeek's Anthropic-compatible endpoint fully supports thinking: disabled — the 400 error is specific to Claude Code's Agent subprocess API request path.

Environment Variable Investigation

We tried setting ANTHROPIC_DEFAULT_SONNET/HAIKU_MODEL=deepseek-v4-flash via three different paths:

  1. settings.json env block
  2. Windows User-level registry (permanent)
  3. Post-restart process inheritance

All three correctly set the env vars (confirmed via echo in subprocesses), but Agent spawn still fails with the same 400 — suggesting the Agent subprocess mechanism bypasses these env vars entirely.

Hypothesis

Claude Code's Agent subprocess API request construction differs from the main conversation path. The subprocess may:

  • Send a parameter or header combination not covered by our direct API tests
  • Use a different HTTP endpoint path
  • Use a different SDK code path that triggers the error

Workaround

Direct execution by Team Lead (no Agent spawn). Quality is unaffected — verified with Critic review scoring 9.0/10 on directly-executed page reviews.

Additional Context

This bug was discovered during systematic /lint --system auditing of a production Obsidian knowledge base (~41K files). The Agent system (Writer/Critic/Researcher with state files, memory, and inter-agent cache channels) was fully deployed but had zero usage over 5 days because every spawn attempt failed silently. The knowledge base has comprehensive self-monitoring protocols that detected the anomaly.

Error Messages/Logs

Steps to Reproduce

Environment

  • Claude Code: v2.1.167 (npm global install)
  • OS: Windows 11 x64
  • API Endpoint: ANTHROPIC_BASE_URL=https://api.deepseek.com/anthropic
  • Main model: ANTHROPIC_MODEL=deepseek-v4-pro (works fine for main conversation)
  • Sub-agent models: ANTHROPIC_DEFAULT_SONNET_MODEL=deepseek-v4-flash, ANTHROPIC_DEFAULT_HAIKU_MODEL=deepseek-v4-flash (set at Windows User env level)

Steps to Reproduce

  1. Configure Claude Code to use DeepSeek's Anthropic-compatible endpoint
  2. ANTHROPIC_BASE_URL=https://api.deepseek.com/anthropic
  3. ANTHROPIC_MODEL=deepseek-v4-pro
  4. Run any Agent spawn: Agent({ model: "sonnet", subagent_type: "general-purpose", ... })
  5. Observe error: API Error: 400 thinking options type cannot be disabled when reasoning_effort is set

Same error occurs with:

  • WebSearch tool
  • WebFetch tool
  • All three Agent model tiers (sonnet/haiku/opus)

What Works

  • Main conversation on deepseek-v4-pro → ✅ perfect
  • All non-subprocess tools (Read, Write, Edit, Bash, Grep, Glob, etc.) → ✅

What We Tested (Direct API Verification)

We ran 11 direct curl tests to DeepSeek's /anthropic/v1/messages endpoint with thinking: {type: "disabled"} combined with various parameters. All returned 200:

| # | model | extra params | Result |
|---|-------|-------------|--------|
| 1 | v4-pro | — | ✅ |
| 2 | v4-pro | tools:[...] | ✅ |
| 3 | v4-pro | tools + system | ✅ |
| 4 | v4-pro | tools + system + tool_choice:{type:"auto"} | ✅ |
| 5 | v4-pro | reasoning_effort:"high" | ✅ |
| 6 | v4-pro | budget_tokens:0 | ✅ |
| 7 | v4-flash | — | ✅ |
| 8 | v4-flash | tools + system | ✅ |
| 9 | claude-sonnet-4-20250514 | Anthropic model ID (mapped to v4-flash by DeepSeek) | ✅ |

This demonstrates that DeepSeek's Anthropic-compatible endpoint fully supports thinking: disabled — the 400 error is specific to Claude Code's Agent subprocess API request path.

Environment Variable Investigation

We tried setting ANTHROPIC_DEFAULT_SONNET/HAIKU_MODEL=deepseek-v4-flash via three different paths:

  1. settings.json env block
  2. Windows User-level registry (permanent)
  3. Post-restart process inheritance

All three correctly set the env vars (confirmed via echo in subprocesses), but Agent spawn still fails with the same 400 — suggesting the Agent subprocess mechanism bypasses these env vars entirely.

Hypothesis

Claude Code's Agent subprocess API request construction differs from the main conversation path. The subprocess may:

  • Send a parameter or header combination not covered by our direct API tests
  • Use a different HTTP endpoint path
  • Use a different SDK code path that triggers the error

Workaround

Direct execution by Team Lead (no Agent spawn). Quality is unaffected — verified with Critic review scoring 9.0/10 on directly-executed page reviews.

Additional Context

This bug was discovered during systematic /lint --system auditing of a production Obsidian knowledge base (~41K files). The Agent system (Writer/Critic/Researcher with state files, memory, and inter-agent cache channels) was fully deployed but had zero usage over 5 days because every spawn attempt failed silently. The knowledge base has comprehensive self-monitoring protocols that detected the anomaly.

Claude Model

Other

Is this a regression?

Yes, this worked in a previous version

Last Working Version

_No response_

Claude Code Version

2.1.167 (Claude Code)

Platform

Other

Operating System

Windows

Terminal/Shell

PowerShell

Additional Information

_No response_

View original on GitHub ↗

14 Comments

yurukusa · 2 months ago

Your test matrix is excellent and it actually contains the answer — there's one cell missing that I think is the whole bug.
Look at what you proved vs. what the subprocess does:

  • v4-pro + thinking:{type:"disabled"} + reasoning_effort:"high" → 200 (your test #5). So v4-pro tolerates the combo.
  • v4-flash + thinking:{type:"disabled"} alone → 200 (#7, #8). So v4-flash tolerates thinking:disabled when reasoning_effort is absent.
  • v4-flash + thinking:{type:"disabled"} + reasoning_effort together → you never tested this cell.

That missing cell is exactly what the Agent path sends. Your sub-agents are mapped to deepseek-v4-flash (ANTHROPIC_DEFAULT_SONNET_MODEL/HAIKU_MODEL), and Claude Code's sub-agent/tool request path sends reasoning_effort and thinking:{type:"disabled"} in the same request (sub-agents disable extended thinking by default to save tokens, while the tier still carries a reasoning_effort). The error string — "thinking options type cannot be disabled when reasoning_effort is set" — is DeepSeek rejecting that combination, and it appears to be model-specific: v4-pro accepts it (#5), v4-flash evidently does not. The main conversation works because it runs on v4-pro.
Two things to try:
1. Confirm it with the one curl you didn't run (this should reproduce the 400 directly, with no Claude Code involved):

curl https://api.deepseek.com/anthropic/v1/messages \
  -H "x-api-key: $KEY" -H "anthropic-version: 2023-06-01" \
  -H "content-type: application/json" \
  -d '{"model":"deepseek-v4-flash","max_tokens":64,
       "thinking":{"type":"disabled"},
       "reasoning_effort":"high",
       "messages":[{"role":"user","content":"hi"}]}'

If that returns the same 400, the bug is the flash model rejecting the pair, not the Agent plumbing per se — which also explains why none of your env-var attempts helped (they set the model correctly; the model is the thing that rejects the combo).
2. Workaround that should unblock you today: point the sub-agent tiers at the model you already proved accepts the combo — deepseek-v4-pro instead of v4-flash:

ANTHROPIC_DEFAULT_SONNET_MODEL=deepseek-v4-pro
ANTHROPIC_DEFAULT_HAIKU_MODEL=deepseek-v4-pro

You lose the flash cost saving on sub-agents, but Agent/WebSearch/WebFetch spawns should start succeeding immediately since v4-pro tolerates thinking:disabled + reasoning_effort (your #5).
If you want to keep flash for sub-agents, the real fix is on the Claude Code side — it should not send reasoning_effort alongside thinking:{type:"disabled"} for the sub-agent path (or should omit one when targeting a model that rejects the pair). Worth noting that in the issue as the upstream ask, with the single curl above as the minimal repro — it's much tighter than the Agent-spawn repro and doesn't depend on your Obsidian setup at all.

PxYu · 2 months ago

Replying to @yurukusa's workaround suggestion:

The workaround does not work. We set every subagent tier to deepseek-v4-pro[1m] (not flash), removed CLAUDE_CODE_EFFORT_LEVEL, verified the env — and Agent spawn still returns the same 400:

ANTHROPIC_DEFAULT_OPUS_MODEL=deepseek-v4-pro[1m]
ANTHROPIC_DEFAULT_SONNET_MODEL=deepseek-v4-pro[1m]
ANTHROPIC_DEFAULT_HAIKU_MODEL=deepseek-v4-pro[1m]   # v4-pro, not flash
CLAUDE_CODE_SUBAGENT_MODEL=deepseek-v4-pro[1m]
# CLAUDE_CODE_EFFORT_LEVEL not set

Agent spawn still fails: API Error: 400 thinking options type cannot be disabled when reasoning_effort is set

The missing curl cell also doesn't reproduce the theory

We ran both of the missing-cell tests directly against DeepSeek:

| model | thinking:disabled + reasoning_effort:"high" | Result |
|-------|---------------------------------------------|--------|
| deepseek-v4-pro[1m] | yes | ✅ 200 |
| deepseek-v4-flash | yes | ✅ 200 |

Both accept the combo. This suggests Claude Code's Agent subprocess request path sends something materially different from what a straightforward curl captures — a different parameter, header, or endpoint path. The bug is in the harness, not in model selection.

Environment: Linux WSL2, Claude Code v2.1.168.

Xuanpei-Zhai · 2 months ago

I also encountered the same problem. All the solutions were ineffective. So I decided to roll back the version.

seedlord · 2 months ago

EDIT2: tweaked the code
https://github.com/seedlord/deepseek-proxy
<img width="1317" height="414" alt="Image" src="https://github.com/user-attachments/assets/1a99c506-ae62-4d70-b92a-50db27ca1f21" />

<details>

DeepSeek Cache-Safe Proxy

A zero-dependency Node.js HTTP proxy that sits between the Claude Code VS Code extension and the DeepSeek API. It inspects, displays, and logs API traffic in a terminal TUI while forwarding requests — with optional subagent thinking overrides.

!Platform
!Node
!Dependencies
<br>🌐 中文文档

!Screenshot

Features

  • Live TUI — Real-time header bar showing port, request count, model, separate MAIN/SUB cache hit rates, toggle states, uptime, and keyboard shortcuts. Scrollable log area with color-coded request/response lines.
  • Subagent thinking override — Automatically injects the main agent's thinking and output_config into subagent requests so they inherit the main session's reasoning budget. Toggle on/off with a single keypress.
  • CSV metrics logging — Records token usage (input, cache hits, output, reasoning), model info, thinking config, tool calls, and more per request. Async, non-blocking writes.
  • Separate cache tracking — MAIN and SUB cache hit rates tracked independently (they have completely separate context caches).
  • Hot reload — Reload all lib/* modules without restarting the process. Log buffer and terminal state are preserved.
  • Pager mode — Freeze the log and scroll through history with vim-like keys (j/k, g/G, PgUp/PgDn). Header stays live.
  • Session detection — Automatically detects API key changes and resets MAIN cache stats for the new session.

Quick Start

# Start the proxy (default port 4000)
node proxy.js

# Custom port
$env:PROXY_PORT=3000; node proxy.js   # PowerShell
PROXY_PORT=3000 node proxy.js         # bash

Then configure Claude Code to use http://localhost:4000 as its API endpoint.

Environment Variables

| Variable | Default | Description |
|---|---|---|
| PROXY_PORT | 4000 | Listening port |
| DEEPSEEK_HOST | api.deepseek.com | Upstream API host |
| PROXY_LOG_FILE | ./proxy-metrics.csv | CSV output path |
| PROXY_MAX_BODY | 52428800 (50 MB) | Max request body size |
| PROXY_REQ_TIMEOUT | 120000 (120s) | Outbound request timeout |
| PROXY_SRV_TIMEOUT | 130000 (130s) | Inbound/server timeout |

Architecture

proxy.js ── orchestrator (HTTP server, forwarding, keyboard input)
  ├── lib/config.js    — constants, env-var overrides, CSV header
  ├── lib/colors.js    — ANSI escapes, log tags, formatting helpers
  ├── lib/tui.js       — terminal UI: header bar, pager/scrollback, cache stats, throttled repaint
  ├── lib/inspector.js — parses Claude API JSON payloads to extract model/thinking/tool info
  └── lib/metrics.js   — extracts token usage from streaming response buffers, writes CSV

Request flow: Client → HTTP server → body read with size cap → JSON parse → payload inspection → session detection (via auth header fingerprint) → subagent thinking override (if applicable) → forward to DeepSeek via HTTPS keep-alive → streaming response → metrics extraction from tail buffer → TUI log + separated MAIN/SUB cache stats + CSV append.

HTTP Endpoints

| Method | Path | Description |
|---|---|---|
| POST | /* | Forward to DeepSeek (JSON body required) |
| GET | /toggle | Toggle subagent thinking override |
| GET | /toggle-log | Toggle CSV file logging |
| GET | /toggle-debug | Toggle debug logging |
| GET | /health | Health check (uptime, request count, toggle states) |
| GET | /status | Brief status (toggles + request count) |
| GET | /metrics | Download CSV log (503 if logging disabled) |

Keyboard Controls

| Key | Action |
|---|---|
| t | Toggle subagent thinking override |
| l | Toggle CSV file logging |
| d | Toggle debug logging |
| r | Redraw screen |
| R | Reset MAIN cache stats (no reload) |
| p | Enter/exit pager mode (scrollback) |
| s | Print stats line to log |
| h | Reset MAIN stats + hot reload all lib/* modules |
| q | Quit |

Pager Mode Keys

| Key | Action |
|---|---|
| j / | Scroll down one line |
| k / | Scroll up one line |
| PageUp | Scroll up 10 lines |
| PageDown | Scroll down 10 lines |
| g | Jump to top of log buffer |
| G | Jump to bottom (resume follow) |
| p / q / Esc | Exit pager, return to follow mode |

CSV Output

Each request appends one row to the CSV log. Columns:

timestamp, role, agentId, model, thinkingType, thinkingBudget, maxTokens, msgCount, systemLen, lastTools, lastUserHint, callTools, missTokens, cacheHitTokens, cacheHitPct, outputTokens, reasoningTokens

  • roleMAIN or SUB (subagent)
  • agentId — first 8 chars of the agent ID
  • cacheHitPct — cache hit rate for this individual request
  • reasoningTokens — DeepSeek reasoning tokens (chain-of-thought)

Requirements

  • Node.js ≥ 18
  • No npm dependencies — uses only http, https, fs, readline built-ins
  • Terminal with ANSI support (Windows 10 1511+, macOS, Linux)

License

MIT

</details>

tianxinliang123 · 2 months ago

我也碰到了同样的问题

tingzhong666 · 2 months ago
For anyone encountering the 400 Bad Request error when using Claude Code (v2.1.166+) with the DeepSeek API, here is a lightweight Node.js proxy workaround. Root Cause Starting with v166, Claude Code intentionally disables thinking for subagent tasks by setting "thinking": { "type": "disabled" }. However, it fails to strip global reasoning parameters (like reasoning_effort or output_config) from the payload. While the official Anthropic API ignores these contradictory fields, DeepSeek's strict API validation rejects them, resulting in a 400 error. Solution Details The proxy script below sits between Claude Code and DeepSeek. It intercepts the JSON payload, checks the thinking state, and strictly removes any conflicting parameters before forwarding the request to the API. It preserves caching and reasoning capabilities for main agent tasks while allowing subagents to execute without crashing. Usage 1. Update your Claude Code settings (~/.claude/settings.json) or environment variables: "env": { "ANTHROPIC_BASE_URL": "http://localhost:4000/anthropic" } 2. Save the script as proxy.js and run it via node proxy.js. View Proxy Code (proxy.js)

测试有效

LeonardoPiel · 2 months ago

the proxy solved my problem. But I would love that anthropic launches an official solution for the problem.

dimulyaekb · 2 months ago

Works perfectly! Thank you @seedlord for the proxy solution. Confirmed working on Claude Code v2.1.169 + DeepSeek v4-pro. WebSearch, WebFetch, and Agent spawn all functional again after setting up this proxy. Saved us from having to downgrade. 🙏

For anyone else finding this: the key is to run the proxy with nohup so it survives terminal sessions, and don't forget to add ANTHROPIC_BASE_URL to the env section of settings.json (not just the shell environment).

guozijing-zjk · 2 months ago

wow,thinks!!!!!!!!!!

Ching-Chiang · 2 months ago

最好的方法,退回165,并且禁用自动更新

guozijing-zjk · 2 months ago
编辑:稍微调整了代码。你现在可以切换“思考”功能给子代理了。 对于在使用 Claude Code(v2.1.166+)搭配 DeepSeek API 时遇到错误的人,这里有一个轻量级的代理Node.js解决方法。400 Bad Request 根因从 v166 开始,Claude Code 有意禁用子代理任务的思考,方法是设置 。然而,它未能从有效载荷中剥离全局推理参数(如或)。官方 Anthropic API 忽略这些矛盾字段,而 Deepseek 严格的 API 验证则拒绝它们,导致 400 错误。"thinking": { "type": "disabled" }reasoning_effortoutput_config 解决方案详情 下面的代理脚本位于Claude Code和DeepSeek之间。它拦截 JSON 负载,检查思维状态,并在将请求转发到 API 前严格删除任何冲突参数。它保留了主代理任务的缓存和推理能力,同时允许子代理执行而不崩溃。 用途 1. 更新你的Claude代码设置()或环境变量:~/.claude/settings.json "env": { "ANTHROPIC_BASE_URL": "http://localhost:4000/anthropic" } 2. 将脚本保存为 ,并通过 运行。proxy.jsnode proxy.js 查看代理代码(proxy.js) const http = require('http'); const https = require('https'); const PORT = 4000; const DEEPSEEK_HOST = 'api.deepseek.com'; // --- LIVE STATE --- let forceSubagentThinking = false; // --- SUBAGENT DETECTION --- // EXPLICIT: x-claude-code-agent-id Header = Subagent function isSubagent(req) { return !!req.headers['x-claude-code-agent-id']; } const keepAliveAgent = new https.Agent({ keepAlive: true, maxSockets: 150, keepAliveMsecs: 5000 }); const server = http.createServer((req, res) => { // --- HTTP API --- if (req.method === 'GET') { if (req.url === '/toggle') { forceSubagentThinking = !forceSubagentThinking; console.log(\n🌐 TOGGLE → [${forceSubagentThinking ? 'ON⚡' : 'OFF'}]); res.writeHead(200, { 'Content-Type': 'application/json' }); return res.end(JSON.stringify({ forceSubagentThinking })); } if (req.url === '/status') { res.writeHead(200, { 'Content-Type': 'application/json' }); return res.end(JSON.stringify({ forceSubagentThinking })); } res.writeHead(404); return res.end('Not Found'); } if (req.method !== 'POST') { res.writeHead(404); return res.end('Not Found'); } let body = ''; req.on('data', chunk => { body += chunk; }); req.on('end', () => { try { let jsonPayload = JSON.parse(body); const clientPath = req.url; if (clientPath.includes('count_tokens')) { console.log([Token Count]); } else { const thinkingType = jsonPayload.thinking?.type || 'MISSING'; const sub = isSubagent(req); const agentId = req.headers['x-claude-code-agent-id'] || '-'; const model = jsonPayload.model || '-'; const msgCount = jsonPayload.messages?.length || 0; console.log([${sub ? 'SUB' : 'MAIN'}] agent=${agentId.substring(0, 10)} model=${model} msgs=${msgCount} thinking=${thinkingType}); if (thinkingType !== 'enabled' && thinkingType !== 'adaptive') { if (forceSubagentThinking && sub) { console.log( ⚡ disabled→enabled); jsonPayload.thinking = { type: 'enabled' }; } else { console.log( ✂ disabled + strip); jsonPayload.thinking = { type: 'disabled' }; delete jsonPayload.output_config; } } else { console.log( → through); } } const modifiedBody = JSON.stringify(jsonPayload); const headers = { ...req.headers }; headers['host'] = DEEPSEEK_HOST; headers['content-length'] = Buffer.byteLength(modifiedBody); const proxyReq = https.request({ host: DEEPSEEK_HOST, port: 443, path: clientPath, method: 'POST', headers: headers, agent: keepAliveAgent }, (proxyRes) => { res.writeHead(proxyRes.statusCode, proxyRes.headers); proxyRes.pipe(res); }); proxyReq.on('error', (err) => { console.error('[Proxy] Error:', err.message); if (!res.headersSent) { res.writeHead(500); res.end('Internal Server Error'); } }); proxyReq.write(modifiedBody); proxyReq.end(); } catch (e) { console.error('[Proxy] Parse error:', e.message); if (!res.headersSent) { res.writeHead(400); res.end('Bad Request'); } } }); }); server.listen(PORT, () => { console.log(==================================================); console.log( Proxy — Header-based detection (x-claude-code-agent-id)); console.log( http://localhost:${PORT}); console.log( FORCE subagent thinking: [${forceSubagentThinking ? 'ON⚡' : 'OFF'}]); console.log(==================================================); console.log( t=toggle s=status q=quit); console.log(==================================================\n); process.stdin.setRawMode(true); process.stdin.resume(); process.stdin.on('data', (key) => { const k = key.toString().toLowerCase(); if (k === 't') { forceSubagentThinking = !forceSubagentThinking; console.log(\n🔧 [${forceSubagentThinking ? 'ON⚡' : 'OFF'}]); } else if (k === 's') { console.log(\n📊 forceSubagentThinking = [${forceSubagentThinking ? 'ON⚡' : 'OFF'}]); } else if (k === 'q') { console.log('\n👋 Done.'); process.stdin.setRawMode(false); process.stdin.pause(); server.close(); process.exit(0); } }); }); 3. 在控制台按T键切换子代理的思维。

Thinks!!!!!!!

blacklc · 2 months ago

Using LiteLLM's proxy hooks to fix the DeepSeek thinking parameter conflict

Thanks to seedlord (@seedlord) for the original idea of using a proxy to strip conflicting parameters before forwarding requests to DeepSeek.

This solution applies to anyone using an LLM gateway (LiteLLM, etc.) to proxy API calls between Claude Code and a third-party LLM provider that strictly validates Anthropic-compatible request schemas.

If you're encountering this 400 error when using Claude Code (v2.1.166+) with DeepSeek API through LiteLLM:

400 Bad Request
"thinking options type cannot be disabled when reasoning_effort is set"

Root Cause

Claude Code v2.1.166+ intentionally sets "thinking": {"type": "disabled"} for subagent tasks to save costs, but fails to strip global reasoning parameters (reasoning_effort, output_config) from the payload. The official Anthropic API tolerates these contradictory fields, but DeepSeek's API strictly validates and rejects them.

Solution

Uses LiteLLM's built-in async_pre_call_hook callback to strip conflicting parameters before the request is forwarded to DeepSeek. No additional proxy process needed — everything runs inside LiteLLM.

Implementation

Create custom_handler.py
from litellm.integrations.custom_logger import CustomLogger


class DeepSeekThinkingFixHandler(CustomLogger):
    async def async_pre_call_hook(self, user_api_key_dict, cache, data: dict, call_type):
        model = data.get("model", "")
        thinking = data.get("thinking")

        # Only modify requests destined for DeepSeek
        if "deepseek" in model.lower():
            if isinstance(thinking, dict) and thinking.get("type") == "disabled":
                data.pop("reasoning_effort", None)
                data.pop("output_config", None)

        return data


proxy_handler_instance = DeepSeekThinkingFixHandler()
Configure LiteLLM to use the handler

Register the callback in your LiteLLM config.yaml:

litellm_settings:
  callbacks:
    - custom_handler.proxy_handler_instance
    # ... your other callbacks (e.g., prometheus)

How It Works

Incoming request (with thinking:disabled + reasoning_effort)
  │
  ├─ Model contains "deepseek"?
  │   ├─ No → Forward as-is (MiniMax, Kimi, etc. unaffected)
  │   └─ Yes → thinking.type == "disabled"?
  │       ├─ No → Forward as-is (main agent requests with reasoning intact)
  │       └─ Yes → Strip reasoning_effort + output_config → Forward
  │
  ▼
DeepSeek API → 200 OK ✅

References

Notes

  • The handler is scoped to DeepSeek models only — other providers (MiniMax, Kimi, etc.) are not affected.
  • Main agent requests with legitimate thinking (e.g. {"type": "adaptive"}) are left untouched.
  • No additional proxy process needed — everything runs inside LiteLLM.
  • The call_type for Anthropic-format requests is anthropic_messages (not pass_through_endpoint).
houleixx · 2 months ago

The 400 thinking options type cannot error happens when the CLI sends a thinking param with an invalid type (e.g., string instead of object, or vice versa). This is a client-side serialization bug — the thinking field should be "thinking": {"type": "enabled", "budget_tokens": N} not "thinking": "enabled" or similar.

If you want to see exactly what the CLI is sending before it hits the API, run it behind a local proxy. The proxy will log the raw JSON body so you can confirm whether the thinking field is malformed. That narrows it down to "is this the CLI or is this my config" instantly.

aromal-a · 1 month ago

If valid object error pass through . Then user should look at usage and the tokens it burn to pass through the description of the prompt and the prompt validation through out the session. Alternative to guided onto on one-one transcription . The idea need to be legitimate and purely recreatable over screen space . The texts that required , The design shape , Curve integrities . The animations of the page that need to follow . The retracted sections of div. Incase if cached . The temporal access via trivia . A small change to deduce complete idea format . If the type was invalid . try changing description of how to curl in it same space dependencies . Ask more questions regarding tkintering , The polishing of substrates to actualize visual description . [Check or whether [The generated matched the outsourced idea]] . If route is able to concat it onto host server and server worker space immediately. . Then it could be easily handled over.

clean tucks of pre-responsive model , Generations proliferated but leaking outwards . Temperature diffused , Matches currentnetdc. If tucks [Ts] are valid . Provide a j-prod . S-son : <Lecture distributed Logics> to counter-rate , The responsive mechanism and loading session via alternate host.