Skip to content

[OpenCode Go / Console Go] OpenAI-compatible chat completions endpoint rejects standard image_url content parts (400: unknown variant image_url, expected text) #40811

Closed as not planned

Description

@lookvincent

Summary

The OpenCode Go ("Console Go") OpenAI-compatible chat completions endpoint rejects any request containing a standard OpenAI image_url content part with HTTP 400 and a raw serde deserialization error — even for models whose actual upstream API (e.g. DeepSeek official API) tolerates images ("unsupported but does not error"). This breaks third-party OpenAI-compatible clients that send images inline (in my case: Codex CLI in responses wire mode → CLIProxyAPI v7.2.120 in OpenAI-compat mode → Console Go /chat/completions).

Error returned

{"error":{"param":null,"type":"invalid_request_error","code":"invalid_request_error","message":"Error from provider (Console Go): Upstream request failed: [invalid_request_error]\nFailed to deserialize the JSON body into the target type: messages[3]: unknown variant `image_url`, expected `text` at line 1 column 76497"}}

Steps to reproduce

Send a standard OpenAI chat completions request with an image content part to the Console Go endpoint (model deepseek-v4-flash):

{
  "model": "deepseek-v4-flash",
  "messages": [
    {"role": "system", "content": "You are a coding agent."},
    {"role": "user", "content": "hello"},
    {"role": "assistant", "content": "hi"},
    {"role": "user", "content": [
      {"type": "text", "text": "what is this?"},
      {"type": "image_url", "image_url": {"url": "data:image/png;base64,iVBORw0KGgo..."}}
    ]}
  ],
  "stream": true
}

Result: HTTP 400 with the serde error above. The identical request with only text content succeeds. The failure is in the request schema, before the model is reached (the error echoes the request body and points at messages[3]).

Why opencode CLI itself never hits this

In opencode CLI, pasted images are stored as file attachments in the session and are not sent inline to the model — the model reads them via tools (e.g. the modlens skill). So the Console Go endpoint is effectively only ever exercised with image_url content parts by third-party OpenAI-compatible clients, which is why this looks fine in the opencode TUI.

Expected behavior

  • Accept standard image_url content parts (pass through, or ignore like the DeepSeek official API does per its docs), OR
  • Return a proper OpenAI-style error envelope instead of echoing a serde error that includes the request body, OR
  • At minimum do not reject the entire request because one message contains an image part.

Environment

  • OpenCode version: latest (1.18.x line), issue filed 2026-08-06
  • Endpoint: Console Go OpenAI-compatible endpoint (opencode-go plan), model deepseek-v4-flash
  • Client path: Codex CLI (wire_api = "responses") → CLIProxyAPI v7.2.120 (openai-compat) → Console Go /chat/completions

Related issues

Activity

  1. github-actions commented on Aug 6, 2026

    @github-actions
    Contributor

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

    If your issue is distinct (e.g. specific to the third-party OpenAI-compatible client path through the Console Go endpoint rather than the VS Code extension), please add a note clarifying the difference so it can be tracked separately.

  2. lookvincent commented on Aug 6, 2026

    @lookvincent
    Author

    Thanks for the triage. This issue is distinct from #31870 and #33942, so a clarifying note:

    Scope: this is specifically the third-party OpenAI-compatible client path: Codex CLI (Responses wire) → CLIProxyAPI (OpenAI-compat mode) → Console Go /chat/completions. It is not the VS Code extension (#31870) and not the zen/go 500 path (#33942).

    Distinct failure mode: a standard OpenAI chat completions request with image_url content parts is rejected with HTTP 400 before reaching the model, via strict serde deserialization:

    Failed to deserialize the JSON body into the target type: messages[3]: unknown variant `image_url`, expected `text`
    

    This is a request-schema rejection (the error echoes the request body), not an upstream model error, and not a 500.

    Why this is effectively the only way to hit it: opencode CLI stores pasted images as file attachments in the session and never sends image_url inline — the model reads them via tools (e.g. the modlens skill). So the Console Go endpoint's image_url handling can only be exercised by third-party OpenAI-compatible clients, which is exactly this case. The actual upstream model API (DeepSeek official) tolerates image parts ("unsupported but does not error" per its docs), so the rejection is entirely at the Console Go gateway schema layer.

    Minimal ask: either accept/ignore standard image_url content parts (matching upstream model behavior), or at minimum return a proper OpenAI-style error envelope instead of a serde error that echoes the request body, so third-party clients can degrade gracefully instead of failing every request that contains an image (including retries that replay the conversation history).

  3. github-actions commented on Oct 7, 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