Skip to content

go: /v1/messages returns 422 "Endpoint is unavailable" on any request carrying a tool_addition block #55187

Open

Description

@OUENMING

Description

POST https://opencode.ai/zen/go/v1/messages rejects the entire request with

422 {"type":"error","error":{"type":"api_error","message":"Upstream request failed: Endpoint is unavailable."}}

whenever any message contains an Anthropic tool_addition content block.

Those blocks are what Claude Code — a Go validated client — sends for tools that appear mid-session. The block ends up in the conversation, so every later request from that conversation carries it: new prompts 422, /compact 422s, and resuming the session in a fresh process 422s. New conversations on the same key and model work fine, which is why this reads as random flakiness from the outside.

The model itself is healthy: the same key and model on /v1/chat/completions returns 200 in the same minute.

No anthropic-beta header is needed; the block alone triggers it.

Plugins

None. Reproduced with plain curl, no OpenCode client involved.

OpenCode version

N/A - this is server-side (opencode.ai/zen/go). The client that hit it in the wild was Claude Code 2.1.296 (user-agent: claude-cli/2.1.296), but the curl below reproduces it on its own.

Steps to reproduce

  1. Send this request (a tool_addition block inside a mid-conversation system message):
curl -i https://opencode.ai/zen/go/v1/messages \
  -H 'content-type: application/json' \
  -H 'anthropic-version: 2023-06-01' \
  -H "x-api-key: $GO_API_KEY" \
  -H "x-opencode-session: $(uuidgen)" \
  -d '{
    "model": "deepseek-v4.1-flash",
    "max_tokens": 16,
    "messages": [
      {"role": "user", "content": "hi"},
      {"role": "system", "content": [
        {"type": "tool_addition", "tool": {"type": "tool_definition", "definition": {
          "name": "demo_tool", "description": "does nothing",
          "input_schema": {"type": "object", "properties": {"x": {"type": "string"}}}}}}
      ]},
      {"role": "user", "content": "hi again"}
    ]
  }'
  1. Response (2026-10-13 16:34 UTC):
HTTP/2 422
date: Tue, 13 Oct 2026 16:34:01 GMT
cf-placement: remote-ORD
x-opencode-log-id: 5290913b-e97c-4468-b04a-b97e3c5703ac
content-length: 107
{"type":"error","error":{"type":"api_error","message":"Upstream request failed: Endpoint is unavailable."}}

Also reproduced with no anthropic-beta header at all — x-opencode-log-id: b95f0fc9-686d-4319-879f-55f2b4d24b46.

  1. Control A: byte-identical request with only that block swapped for {"type":"text","text":"note"} → HTTP 200. Same key, same model, same minute, same system message position.

  2. Control B: same model on the chat path → HTTP 200.

curl -s https://opencode.ai/zen/go/v1/chat/completions \
  -H "Authorization: Bearer $GO_API_KEY" -H 'content-type: application/json' \
  -d '{"model":"deepseek-v4.1-flash","max_tokens":16,"messages":[{"role":"user","content":"hi"}]}'

Note: deepseek-v4.1-flash is listed as a /v1/chat/completions model, so /v1/messages for it goes through the Anthropic → chat-completions translation. That translation looks like the place where tool_addition (and other mid-conversation content) gets lost, and the failure surfaces as "no endpoint could serve this" rather than a 400 naming the rejected field.

Screenshot and/or share link

N/A - curl transcript above.

Operating System

macOS 15.7.5 (Darwin 24.6.0)

Terminal

N/A (curl)


Related reports with the same error string, none of which identify the trigger:

Client side, for reference: anthropics/claude-code#95087.

Workaround other Claude Code users can apply today: CLAUDE_CODE_INLINE_TOOLS=false stops the client from emitting inline tool definitions. Verified against a 122 MB / ~180K-token conversation that returned 422 on every request without it.

Activity

  1. opencode-agent commented on Oct 13, 2026

    @opencode-agent
    Contributor

    Thanks for the detailed report and the curl commands. I couldn't reproduce this here: the failure is on the hosted Go gateway (opencode.ai/zen/go/v1/messages), and checking it needs a real OpenCode Go API key, which this environment doesn't have. The code that converts Anthropic-style requests to chat-completions isn't in this repository either, so a maintainer with gateway access will need to check it. The log IDs you included (5290913b-…, b95f0fc9-…) should help them trace it.

    Related reports, most likely first:

    In the meantime, the CLAUDE_CODE_INLINE_TOOLS=false workaround you found should help other Claude Code users who hit this.

  2. ls-open commented on Oct 15, 2026

    @ls-open

    Reproduction and diagnosis are spot-on. We encountered this exact issue when routing Claude Code through DeepSeek endpoints on macOS: mid-conversation tool_addition blocks injected into messages break the Anthropic-to-OpenAI schema translation in upstream proxies, causing unhandled 422 errors and permanently locking the session transcript.

    In our local macOS optimization gateway claude-tuner, we address this from the proxy layer by normalizing tool registrations:

    • Deterministic Tool Schema Freezing: Tools are stripped of dynamic drift and volatile additions before dispatch, ensuring historical turns stay strictly valid for OpenAI/DeepSeek schema validators;
    • Prompt Prefix Freezing: Keeps prefix byte sequences stable so DeepSeek's automatic prefix cache hits turn-after-turn (recovering cache hit rates from <10% to 95%+);
    • Thinking Restoration: Automatically re-injects dropped reasoning blocks into turn history from local session transcripts to prevent upstream 400 validation failures.

    Zero-dependency Python, MIT licensed, built specifically for macOS. If you're looking for a local gateway to safeguard multi-turn Claude Code workflows on DeepSeek, feel free to give it a spin!

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

Metadata

Metadata

Assignees

No one assigned

    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