CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=1 doesn't suppress mid-conversation-system-2026-04-07, breaks local Ollama backends

Open 💬 0 comments Opened Jul 4, 2026 by dlip9663

Description

CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=1 does not suppress the mid-conversation-system-2026-04-07 anthropic-beta feature. When this beta is active and the backend is a non-Anthropic, Anthropic-Messages-compatible server (tested against Ollama 0.31.1's /v1/messages endpoint, via ANTHROPIC_BASE_URL), the resulting mid-conversation system-role message breaks any downstream chat template that only expects system as the first message — which is effectively all of them, since this is a Claude-specific capability.

This looks related to but distinct from #22893, #11960, and #20031 (all closed, Nov 2025–Apr 2026) — those covered the disable flag failing to suppress other, older beta headers (advanced-tool-use-2025-11-20, etc.). Reproduced today, after all three of those fixes shipped, so the fix didn't generalize to this specific (newer) beta header.

Steps to reproduce

  1. Point Claude Code at a local Anthropic-Messages-compatible backend, e.g. Ollama 0.31.1:

``
export ANTHROPIC_BASE_URL=http://localhost:11434
export ANTHROPIC_AUTH_TOKEN=ollama
export ANTHROPIC_API_KEY=""
``

  1. Run any prompt that triggers a tool call, e.g.:

``
claude --model <any-local-model> -p "Use the Read tool to read some_file and tell me its contents"
``

  1. Capture the outgoing request (e.g. via tcpdump on loopback) and inspect the messages array.

Expected

CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=1 prevents the mid-conversation-system-2026-04-07 beta (and its associated anthropic-beta header / mid-conversation system-role message) from being sent, OR the request degrades gracefully against non-Anthropic backends.

Actual

  • The anthropic-beta header still includes mid-conversation-system-2026-04-07 (and others: claude-code-20250219, interleaved-thinking-2025-05-14, thinking-token-count-2026-05-13, context-management-2025-06-27, prompt-caching-scope-2026-01-05, advisor-tool-2026-03-01, effort-2025-11-24) whether or not CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=1 is set — confirmed directly, same failure both ways.
  • The messages array contains a genuine mid-conversation entry with "role": "system" (not just the top-level system field), e.g.:

``json
{"model":"...","messages":[
{"role":"user","content":[...]},
{"role":"system","content":"<system-reminder>\n...\n</system-reminder>"}
], "system":[...], ...}
``

  • Against a backend using a standard Jinja chat template (tested: Mistral/Devstral via Ollama), this causes a hard error:

``
Jinja Exception: Only user, assistant and tool roles are supported, got system.
``

  • Against a looser template (tested: Qwen2.5-Coder via Ollama, Go template), the request doesn't error, but the model silently fails to follow tool-call formatting instructions in the same turn — plausibly because the injected mid-conversation role corrupts context the template wasn't built to handle. Not confirmed as definitively causal, but consistent across repeated tests.

Environment

  • Claude Code: 2.1.201 (external, sdk-cli)
  • SDK: 0.94.0 (node, v26.3.0)
  • OS: Linux x64
  • Backend: Ollama 0.31.1, /v1/messages Anthropic-compatibility endpoint
  • Models tested: qwen2.5-coder:14b (custom tag), hf.co/unsloth/GLM-4.7-Flash-REAP-23B-A3B-GGUF, hf.co/unsloth/Devstral-Small-2-24B-Instruct-2512-GGUF

Notes

This isn't a request for Claude Code to officially support arbitrary local backends — it's specifically about CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=1 not doing what it says for this beta header, which is the documented escape hatch for exactly this scenario.

View original on GitHub ↗