Skip to content

Zen /v1/responses (glm-5.3-flash): 422 "Input should be a valid string" when a tool output contains an image — bricks Codex screenshot/browser sessions #48740

Closed as not planned

Description

@SiliconDawnNo-1

Summary

Through the Zen Go plan /v1/responses endpoint with glm-5.3-flash, any Codex session in which the browser/computer-use plugin returns a screenshot as a tool output (function_call_output whose output is an array containing input_image) fails with HTTP 422 on every subsequent request:

{"error":{"param":"messages.14.user.content.str","type":"invalid_request_error","message":"Error from provider (Console Go): Upstream request failed: [invalid_request_error] Input should be a valid string"}}

The image itself is fine — the model demonstrably has working vision through this endpoint when the image arrives in a user message. This looks like a Responses→Chat conversion bug: the image-bearing tool output gets mapped to a message branch that requires content to be a plain string.

Environment

  • Client: OpenAI Codex CLI 0.151.0 / Codex desktop, wire_api = "responses", disable_response_storage = true (full history re-sent every turn)
  • Provider: Zen Go plan, base …/zen/go/v1, model glm-5.3-flash (catalog: input_modalities: ["text", "image"])
  • Via cc-switch local proxy; observed 2026-09-13

Evidence

A. Real session (21 input items, browser task). Six function_call_output items; five are plain-text arrays and pass; the single one containing [{"type":"input_text",…},{"type":"input_image","image_url":"data:image/jpeg;base64,…"}] (a ~7 KB Chrome-tab screenshot) is rejected as messages.14.user.content.str. 7 consecutive retries → identical 422 (plus one 504). The session is unusable from that point on.

B. Same session, image replaced by a text placeholder → HTTP 200, complete history (~66k tokens) processed and the model continues the task normally. So the poisoned item is exactly the image-in-tool-output.

C. Vision works through this channel when the image is in a user message:

  • Minimal probe: user message + valid 8×8 red PNG → 200, model answers “红色” (red) correctly.
  • Full 90k-token session context with the same image appended to the last user message → 200, correct color answer + task continues.

D. Minimal 3-item probe (user message → paired function_call → function_call_output with text+image array) → 200 and the model describes the screenshot correctly.

So the failure is not image support per se, and not the paired-output shape alone — it appears in longer multi-turn sequences (multiple prior tool outputs / reasoning items), pointing at message-branch selection in the Responses→Chat converter (or Console Go's validation) for image-bearing tool outputs.

Impact

Every Codex session using browser/computer-use plugins bricks after the first screenshot; all retries 422 with no recovery path short of editing the client-side session file.

Related issues

Request

Please make the Responses→Chat conversion map input_image parts inside function_call_output to a vision-capable message (or at least fail with a descriptive error) instead of the string-content branch. Happy to provide the full captured session payloads (sanitized) if useful.

Activity

  1. gy6221 commented on Sep 15, 2026

    @gy6221

    Additional reproduction that bypasses both cc-switch and the Responses-to-Chat conversion:

    Direct POST https://opencode.ai/zen/go/v1/chat/completions with glm-5.3-flash. The image is already in the final role: "user" content; there is no function_call_output and no /v1/responses request involved.

    Message shape:

    [
      {"role": "system", "content": "s"},
      {"role": "user", "content": "start"},
      {"role": "assistant", "content": null, "tool_calls": [{"id": "c0", "type": "function", "function": {"name": "f", "arguments": "{}"}}]},
      {"role": "tool", "tool_call_id": "c0", "content": "result 0"},
      {"role": "assistant", "content": null, "tool_calls": [{"id": "c1", "type": "function", "function": {"name": "f", "arguments": "{}"}}]},
      {"role": "tool", "tool_call_id": "c1", "content": "result 1"},
      {"role": "assistant", "content": null, "tool_calls": [{"id": "c2", "type": "function", "function": {"name": "f", "arguments": "{}"}}]},
      {"role": "tool", "tool_call_id": "c2", "content": "result 2"},
      {"role": "assistant", "content": null, "tool_calls": [{"id": "c3", "type": "function", "function": {"name": "f", "arguments": "{}"}}]},
      {"role": "tool", "tool_call_id": "c3", "content": "result 3"},
      {
        "role": "user",
        "content": [
          {"type": "text", "text": "screenshot"},
          {
            "type": "image_url",
            "image_url": {
              "url": "data:image/png;base64,...",
              "detail": "original"
            }
          }
        ]
      }
    ]

    Observed intermittently:

    {
      "error": {
        "param": "messages.10.user.content.str",
        "type": "invalid_request_error",
        "message": "Error from provider (Console Go): Upstream request failed: [invalid_request_error] Input should be a valid string"
      }
    }

    Results so far:

    • 4 tool-call/tool-result pairs followed by the image-bearing user message: 1 of 4 requests returned 422.
    • 2 pairs followed by the same message: 1 of 6 requests returned 422 in another run.
    • The same message history without the image returns 200.
    • A text-only content array after the same tool history returns 200.
    • A single tool-call pair followed by the image message has returned 200.
    • Moving the image before the tool-call history has returned 200.

    This means function_call_output is not required to trigger the error, and the issue also reproduces when clients send Chat Completions directly to OpenCode Go. The remaining trigger appears to be a context-dependent combination of multi-turn tool history, an image-bearing user.content array, and the backend/route selected for that session.

    It may therefore be worth broadening the title/scope beyond the Responses-to-Chat conversion path.

  2. opencodejr commented on Oct 28, 2026

    @opencodejr

    Thanks for the detailed write-up. Narrowing it down to an input_image inside a function_call_output makes this much easier to look into.

    This is a problem with the hosted Zen / OpenCode Go /v1/responses endpoint, not with the OpenCode app. You're calling it from Codex CLI, and the conversion that fails runs on the service side. Its code isn't in this repository, so it can't be fixed or tracked here. Zen and Go service problems like this are handled by the team directly rather than in GitHub issues. Please email help@anoma.ly with:

    • this summary and a link to this issue
    • the sanitized session payloads you offered
    • roughly when it happened (2026-09-13)

    If you've already emailed, the team will get to it, especially now that we've seen it here. Please keep API keys, account details and email addresses out of this public issue and put them only in the email.

    Related issues you linked, for context (all closed):

    The bot will close this issue in 1 day.

  3. opencodejr commented on Oct 29, 2026

    @opencodejr

    Closing this now, @SiliconDawnNo-1: this is a problem with the hosted Zen / OpenCode Go /v1/responses endpoint, which the team handles directly rather than through GitHub issues. If you haven't already, please email help@anoma.ly with the summary from this issue and your sanitized session payloads. Keep keys and account details out of this public thread and put them only in the email. Thanks again for the thorough investigation.

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions