Repository navigation
Description
Summary
With OpenCode Go, models served over the Anthropic Messages route (for example opencode-go/qwen3.8-flash) surface every upstream rejection as the opaque message Provider request failed with HTTP 400. The route returns an empty error payload, so the real upstream reason (for example a content-filter rejection) is lost and the user cannot tell what failed.
Environment
- opencode version: 2.0.18
- OS: Darwin 27.0.0 (darwin arm64)
- Terminal: Kaku (
TERM_PROGRAM=Kaku,TERM=xterm-256color,COLORTERM=truecolor) - Shell: /bin/zsh
- Install/channel: Homebrew (
opencode-v22.0.18), channel latest - Active plugins: local
rtkplugin (shell command rewrite only; unrelated to provider requests)
Reproduction
- Connect OpenCode Go and select a model whose catalog entry uses the Anthropic runtime, e.g.
opencode-go/qwen3.8-flash(package: "@opencode/ai/providers/anthropic",settings.baseURL: "https://opencode.ai/zen/go/v1"). - Build a session whose context the upstream rejects. In my case a long assistant text (a NetBird/DNS investigation, ~11.5k chars) trips Alibaba's Qwen content filter.
- Send any next prompt in that session (or call
POST /api/session/:sessionID/generate). - The step fails with
Provider request failed with HTTP 400and no further detail.
Network-level, the request is POST https://opencode.ai/zen/go/v1/messages and the response is HTTP 400 with body:
event: error
data: {}
An SSE error event whose payload is an empty object. With stream: false the same request returns:
{"model":"qwen3.8-flash"}Neither body carries error.message or code.
Expected Behavior
The upstream rejection should be surfaced with its real message so the user can act on it. In this case the underlying reason is knowable: the same content sent over the OpenAI-compatible runtime (POST /chat/completions) returns
{"error":{"param":null,"type":"server_error","message":"Upstream request failed: [data_inspection_failed] <400> InternalError.Algo.DataInspectionFailed: Input text data may contain inappropriate content."}}Actual Behavior
opencode can only report Provider request failed with HTTP 400. In opencode 2.0.18 the error mapping for provider HTTP errors falls back to Provider request failed with HTTP <status> whenever the response body has no message/code (see XC() near Provider request failed with HTTP ${e.statusCode} in the server bundle). Because the Anthropic route returns data: {}, there is nothing to surface.
Additional Context
- The failure is deterministic for a given context, so retrying the same prompt keeps failing with the same opaque 400.
- Workaround that restores the real message: override the model's runtime so requests use the OpenAI-compatible endpoint, which preserves the upstream error body:
{
"providers": {
"opencode-go": {
"models": {
"qwen3.8-flash": {
"package": "@opencode/ai/providers/openai-compatible"
}
}
}
}
}After this override the same step reports Upstream request failed: [data_inspection_failed] <400> InternalError.Algo.DataInspectionFailed: Input text data may contain inappropriate content.
- Two possible fixes on the OpenCode side:
- When the Anthropic route receives an error event with an empty payload, fall back to the raw HTTP response body/status text so the message is not silently dropped.
- Have the Go gateway include the upstream
error.messagein the Anthropic error event instead of{}.
Activity
github-actions commentedon Sep 26, 2026
This issue might be a duplicate of existing issues. Please check:
/v1/messagesreturns a 400 with an empty error payload; the report asks for a descriptive error.a-d-gordienko commentedon Sep 29, 2026
Same failure here with
opencode-go/qwen3.8-flash— adding data points from a different platform, in case they help narrow it down:Environment
opencode-go/qwen3.8-flashBad Request: event: error data: {}Deterministic — 5/5 attempts on 2026-09-29 (both
planandbuildagents):Control: in the same session/environment
opencode-go/deepseek-v4.1-flashworks fine, so the Go subscription/auth is not the issue — onlyqwen3.8-flashfails.This matches the empty
event: error+data: {}payload described in the issue. Happy to run further diagnostics (fresh session, local recording endpoint for the request body) if that would help.VictorHMH18713 commentedon Oct 27, 2026
Related data point on the same route, different masking shape.
ANTHROPIC_BASE_URL=https://opencode.ai/zen/go, modeldeepseek-v4.1-flash,stream: true.event: errorwith{}, we get HTTP 400 with a 0-byte body (curl reportsContent-Lengthabsent, 0 bytes read), which Claude Code renders asAPI Error: 400 status code (no body).stream: falsereturns the real upstream reason:Since Claude Code does not retry 400 (
408 / 409 / 429 / 5xx / x-should-retry: trueonly), the empty 400 is terminal there: it killed 8 of 25 workflow subagents in a 20-minute window. Any upstream error text (SSE event or plain JSON body) would at least let the client surface and report it.opencodejr commentedon Oct 28, 2026
Thanks for the detailed report. I reproduced this with a local mock in place of the OpenCode Go Anthropic route. The mock returns what you and #57122 observed: HTTP 400 with
event: error/data: {}. A provider using@opencode/ai/providers/anthropicpointed at it gives:Provider request failed with HTTP 400, with no further detail.dev(86ce19d):Provider request failed with HTTP 400: event: error data: {}. Since fix(ai): show provider error bodies when no message is recognized #51978 the raw response body is appended, which is your first suggested fix. Because the gateway sends an empty payload, the real upstream reason still never reaches you.The remaining problem looks like the Go gateway dropping the upstream error on the Anthropic route for qwen3.8 (your second suggestion). That gateway isn't in this repo, so I couldn't test it directly. Your workaround (overriding the model's
packageto@opencode/ai/providers/openai-compatible) is the way to see the real message for now.Related: #57122 (a deterministic curl reproduction of the same empty
data: {}error) and #52791 (probably the same empty error frame showing up as an invalid stream event). The script below reproduces this against a mock server.Reproduction script (repro.sh)
Run it:
bash repro.sh