Skip to content

Zen returns 400 Upstream request failed when thinking is enabled for latest Claude models (fable-5, sonnet-5, opus-4-8); older models (opus-4-6, haiku-4-5) work fine #35124

Closed as not planned

Description

@ocelot43

Description

Summary

When calling the Zen Anthropic-messages endpoint (POST https://opencode.ai/zen/v1/messages) with an explicit thinking: { type: "enabled", ... } parameter, three of the newest Claude models fail with a 400 invalid_request_error — Error from provider (Console): Upstream request failed. The exact same request body succeeds for the previous-generation models. Without the thinking parameter all of these models return 200, so the trigger is specifically the extended-thinking parameter path, not the models being unavailable.

Downstream impact: because extended-thinking round-trips fail (or silently degrade to non-thinking), assistant turns come back with no thinking block / signature. In multi-turn tool-use sessions this breaks Anthropic prompt-caching of the conversation history (the cached prefix no longer matches byte-for-byte from the first tool call onward), so the entire history is re-billed at full input price every turn. On a ~120k-token fable tool-loop session this showed up as a constant ~$0.033 cache saving (only tools+system cached, ~3.7k tokens) while 120k of history was re-charged each turn.

Environment

  • Endpoint: https://opencode.ai/zen/v1/messages (Anthropic messages API, x-api-key auth)
  • anthropic-version: 2023-06-01
  • Isolated by stepping down through layers to rule out client-side variables: first seen as odd caching/cost behavior in an opencode session → reproduced in a second, unrelated client → then reproduced with raw curl and no client at all (matrix + repro below). Same failure across all three, so it's purely server-side (the Zen→upstream hop), not client-specific.

Minimal reproduction

KEY=<your zen key>

# FAILS (400) — claude-fable-5, claude-sonnet-5, claude-opus-4-8
curl -s -X POST "https://opencode.ai/zen/v1/messages" \
  -H "x-api-key: $KEY" -H "anthropic-version: 2023-06-01" -H "content-type: application/json" \
  -d '{"model":"claude-fable-5","max_tokens":2000,"thinking":{"type":"enabled","budget_tokens":1024},"messages":[{"role":"user","content":"hi"}]}'
# -> 400 {"type":"error","error":{"type":"invalid_request_error","message":"Error from provider (Console): Upstream request failed"}}

# WORKS (200) — same body, claude-haiku-4-5 / claude-opus-4-6
curl -s -X POST "https://opencode.ai/zen/v1/messages" \
  -H "x-api-key: $KEY" -H "anthropic-version: 2023-06-01" -H "content-type: application/json" \
  -d '{"model":"claude-haiku-4-5","max_tokens":2000,"thinking":{"type":"enabled","budget_tokens":1024},"messages":[{"role":"user","content":"hi"}]}'
# -> 200, content = [thinking(signature len ~424), text]

Test matrix (identical request body, only model changes)

Model thinking enabled no thinking param
claude-fable-5 400 Upstream request failed 200 ([thinking, text], adaptive)
claude-sonnet-5 400 Upstream request failed 200 ([text])
claude-opus-4-8 400 Upstream request failed 200 ([text])
claude-opus-4-6 200 ([thinking, text], signature len 368) 200
claude-haiku-4-5 200 ([thinking, text], signature len 424) 200

The failure is cleanly correlated with the newest model generation. Note claude-fable-5 even emits a thinking block on its own when no thinking param is sent, so the model clearly supports thinking — it's the explicit thinking parameter path on the Zen→upstream hop that is broken for these three models.

Expected

thinking-enabled requests for claude-fable-5 / claude-sonnet-5 / claude-opus-4-8 should return 200 with a thinking block (including a valid signature), same as opus-4-6 / haiku-4-5.

Actual

400 invalid_request_error — Error from provider (Console): Upstream request failed. The upstream error detail is not surfaced, which also makes this hard to diagnose from the client side.

Notes / asks

  • Could you surface the real upstream error body instead of the generic "Upstream request failed"? It would make issues like this self-diagnosable.
  • This looks like a server-side issue in the (closed) Zen API itself, not in the open-source opencode client — it reproduces with raw curl against opencode.ai/zen, independent of any client. I'm filing it here since this is the escalation path to whoever operates Zen; I can only report it, not patch it. Likely a per-model config/routing issue for the newest Claude generation on the Zen→upstream hop (e.g. a thinking / budget_tokens / beta-header mismatch).
  • Full disclosure on the cost side: before I tracked this down, I'd already spent roughly $60 on fable-5 tool-loop sessions that were silently re-billing the full conversation history every turn because of this caching breakage. I'm not claiming anything owed — but if the team felt like extending some credit toward the time spent isolating and reporting this, I'd genuinely appreciate it. Happy to provide more repro cases, request/response captures, or usage/request IDs to help you trace it upstream.

Plugins

No response

OpenCode version

No response

Steps to reproduce

No response

Screenshot and/or share link

No response

Operating System

No response

Terminal

No response

Activity

  1. github-actions commented on Sep 2, 2026

    @github-actions
    Contributor

    To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions