Skip to content

opencode-go/deepseek-v4.1-flash randomly rejects requests with 400/403 #51434

Closed as not planned

Description

@mysterious75

Description

I'm hitting random failures with deepseek-v4.1-flash on the opencode-go provider. The session just stops with:

Bad Request: {"model":"deepseek-v4.1-flash"}

Sometimes I also see it come back as a 403 with error code: 1010 when I replay the same request by hand.

It happens after a few turns where the assistant made tool calls (MCP tools, all of them completed fine). Nothing special happens right before it - no interrupt, no crash. It just fails on an ordinary tool call turn.

I pulled the message history for the failed turn straight out of ~/.local/share/opencode/opencode.db and sent the exact same messages array to https://opencode.ai/zen/go/v1/chat/completions with a valid key and session header. The gateway still rejects it, so it's not a client-side bug.

Happens on both my machines with the same setup. I'm on the latest version (1.18.32), so there's nothing to upgrade to.

Plugins

none

OpenCode version

1.18.32

Steps to reproduce

  1. Start a session on opencode-go with deepseek-v4.1-flash, with a few MCP servers connected (I used railway).
  2. Let it run through several turns where the assistant calls tools and gets results back normally.
  3. On one of the next turns the request fails with Bad Request: {"model":"deepseek-v4.1-flash"}.
  4. Open ~/.local/share/opencode/opencode.db (sqlite), pull the messages/parts for the failed assistant message, and rebuild the same messages[] array.
  5. POST it to https://opencode.ai/zen/go/v1/chat/completions with model: deepseek-v4.1-flash, a valid Authorization header and x-opencode-session.
  6. Gateway returns 403 error code: 1010 (or 400 with just the model name in the body).

Failing message in my case: msg_0db775f66001N2FWEzAPquvNsT.
One thing I checked — every tool part in that history has state.status: "completed". So this isn't a dangling or half-finished tool call.

Image

Screenshot and/or share link

No response

Operating System

Windows 11

Terminal

Windows Terminal (PowerShell)

Activity

  1. github-actions commented on Sep 26, 2026

    @github-actions
    Contributor

    This issue might be a duplicate of existing issues. Please check:

  2. chinarma commented on Sep 27, 2026

    @chinarma

    every 8-10 step happens 。

  3. SamSpiri commented on Sep 29, 2026

    @SamSpiri

    Client-side workaround for the retry gap described here.

    https://github.com/SamSpiri/opencode-go-stub-400-retry

    It implements the second paragraph of the Expected Behavior above: a 400 whose body carries no error information is retried a couple of times instead of ending the turn. Structured 400s keep the built-in policy, so deterministic rejections are not retried pointlessly.

    Single file, no dependencies. Install by copying it into ~/.config/opencode/plugins/; it uses the V2 session.hook("retry") API, and OpenCode discovers files in that directory automatically, so there is no config to edit. It matches only: provider opencode-go + model deepseek-v4-flash / deepseek-v4.1-flash + status 400 + provider.invalid-request + an opaque message (the Provider request failed with HTTP 400 fallback, a bare Bad Request, or the raw {"model":"..."} body). Two extra attempts, 3 s then 9 s.

    Worth stating plainly:

    I have not observed it fire on a live stub, since that can't be induced on demand. What I did verify: the matcher against the shapes an empty-body 400 can take, and that the surfaced message really is the client fallback rather than a gateway string — from the 2.0.19 provider-error path, where the status-derived Provider request failed with HTTP ${status} is used whenever the parsed body yields no message/code.

    If an upstream change is preferred over a plugin, the smallest version is #50574's item 1: propagate the provider response body into the classifier so isContextOverflowError can see it, and treat a 400 with no error information as retryable once.

  4. SamSpiri commented on Oct 2, 2026

    @SamSpiri

    Correction to my earlier comment, with results.

    My first version of this did not fire, and the reason is worth recording: the message is not stable across versions. On 2.0.19 a bodyless 400 persisted as the bare Provider request failed with HTTP 400. On 2.0.21 it arrives as

    Provider request failed with HTTP 400: {"model":"deepseek-v4.1-flash"}
    

    — the raw body appended — and the stub is additionally persisted at error.response.body. A matcher anchored ^...$ on the bare form silently no-ops on the second shape. That is what happened on a machine of mine that hit this today, plugin loaded and active.

    Fixed, and now verified end to end rather than assumed. Pointing a throwaway provider at a local server that answers 400 with {"model":"deepseek-v4.1-flash"} for the first three requests:

    plugin requests observed outcome
    disabled 3, all 400, same second turn fails: Provider request failed with HTTP 400
    enabled 4 — the three, then one 9.1 s later returning 200 turn completes

    Without it the turn dies exactly as reported here; with it the retry carries the turn through. That is a direct demonstration of the retryability claim in this issue, on a client that otherwise treats the 4xx as terminal.

    Two points that may help the actual fix:

    • On 2.0.21 the stub is retained, at error.response.body on the persisted assistant message. The client can therefore distinguish an empty-body 400 from a structured one without any gateway change — which is most of what this issue's Expected Behavior asks for.
    • Anything keying off the message text should not anchor on the bare fallback form, since it is version-dependent.

    Updated plugin: https://github.com/SamSpiri/opencode-go-stub-400-retry

  5. thdxr commented on Oct 11, 2026

    @thdxr
    Member

    Thanks for the report! OpenCode 2.0 is now out and development is focused on V2, so we're closing issues filed against OpenCode 1. Please upgrade (opencode upgrade --major, details: https://anoma.ly/notes/opencode-2-0), and if this is still relevant on 2.0, reopen this issue or open a new one with your 2.0 version.

    — from 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊

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