Skip to content

[server]: provider transport decode error during tool call permanently poisons session "Schema validation failed" #51117

Closed as not planned

Description

@xDFCx

Summary

A tool call that is interrupted mid-stream by a provider transport error (Decode error (200 POST <redacted-proxy-url>/v1/chat/completions)) is persisted into session history in a shape that fails SessionModelRequest.prepare schema validation. Every subsequent message in that session fails with Session failed / Schema validation failed — the session becomes permanently unusable (even after switching models, since validation happens before provider selection).

Environment

  • opencode version: 2.0.15
  • OS: Linux 6.6.87.2-microsoft-standard-WSL2 (x86_64)
  • Terminal: TERM=xterm-256color
  • Shell: /bin/bash
  • Install/channel: latest (release)
  • Active plugins: @cortexkit/opencode-magic-context@latest
  • Provider: @ai-sdk/openai-compatible against a self-hosted LiteLLM proxy (URL redacted), model free_glm-5.3-flash (OpenAI-compatible chat completions)

Reproduction

  1. Configure an OpenAI-compatible provider (LiteLLM proxy in my case).
  2. Run a session where the model emits a tool call and the provider returns a response body that fails client-side decoding mid-stream (observed with GLM 5.3 Flash via LiteLLM: HTTP 200 with an undecodable body during a shell tool call).
  3. The interrupted turn is persisted. In the storage record the tool item looks like this (note input: {}, no content, finish: "error" on the message):
    {
      "type": "tool",
      "id": "chatcmpl-tool-…",
      "name": "shell",
      "executed": false,
      "state": {
        "status": "error",
        "input": {},
        "error": {
          "type": "provider.transport",
          "message": "Decode error (200 POST https://<redacted-proxy-url>/v1/chat/completions)",
          "status": 200
        }
      }
    }
  4. Send any follow-up message (or "continue") in the same session.

Expected Behavior

The failed tool call should be sanitized into a valid history item (e.g. a tool-result with type: "error"), and the session should continue working.

Actual Behavior

Every drain of the session fails with:

ERROR Failed to drain Session cause="Error: Schema validation failed
    at SessionModelRequest.prepare (...)
    at SessionRunner.runStep (...)
    at SessionRunner.drain (...)

The embedded Effect Schema issue points at the tool item: Pointer path=["content"] → Pointer path=[3] → AnyOf over LLM.Content.* (Text/Media/ToolCall/ToolResult/Reasoning/Compaction/Effort) with zero matching members — i.e. the persisted shape of the interrupted tool item matches no allowed content variant.

Observed 12+ consecutive failures, all for the same session:

timestamp=… level=ERROR message="Failed to drain Session" sessionID=ses_… cause="Error: Schema validation failed"

After the first failure, every new user message in that session immediately ends with type: "idle", outcome: "failed" — no assistant message is created. Switching models does not help (validation runs before the provider is contacted). Other sessions in the same project with normal tool errors validate fine, which isolates the problem to the provider.transport decode-error tool item shape:

  • tool item with status: "error", error type: "tool.execution" (permission rejection) → drains OK
  • tool item with status: "error", error type: "aborted" → drains OK
  • tool item with status: "error", error type: "unknown" (tool cancelled) → drains OK
  • tool item with status: "error", error type: "provider.transport" (decode error mid tool-call, empty input) → permanently poisons the session

Related Issues

Additional Context

  • The trigger on the provider side was a single malformed response from a LiteLLM proxy (GLM 5.3 Flash, OpenAI-compatible endpoint). One bad response permanently bricks the session.
  • Only workaround found: abandon the session and start a new one; the broken session remains readable but cannot accept messages. Model switching and service restart do not help.
  • Suggested fix directions: sanitize orphaned/failed tool calls in SessionModelRequest.prepare (map error-state tool items to a valid LLM.Content.ToolResult with type: "error"), and/or validate/sanitize the persisted message when it is written, not on every subsequent drain. This complements the fix in PR fix(core): degrade malformed tool-result content instead of crashing prepare #50776, which only guards the in-memory .map path.
  • Logs available on request (redacted). Storage record and full Effect Schema issue dump were inspected locally; happy to attach them.

Activity

  1. opencode-agent commented on Oct 22, 2026

    @opencode-agent
    Contributor

    Closing as won't fix. This is caused by the @cortexkit/opencode-magic-context plugin, not by OpenCode core.

    The plugin registers a V2 session.hook("context") that rewrites the outgoing messages. When it restores folded history (restoreRow), it builds errored tool results by hand as { type: "tool-result", ..., result: { error, content }, resultType: "error" }. That is not a valid LLM.ToolResult because result has no type, so building the request fails with Schema validation failed on content → [n] → AnyOf. That matches the trace in this report. Rows outside the plugin's restored range go through OpenCode's own lowering and are fine, which is why other errored tools appeared to work.

    What we checked:

    • OpenCode's own lowering of the exact stored record above (an errored shell tool with input: {} and a provider.transport error) gives a valid tool-call and error tool-result pair on both v2.0.15 and current dev. The tool-error lowering in to-llm-message.ts hasn't changed since v2.0.15.
    • Building a message with the plugin's restored shape reproduces this exact schema failure.
    • The latest plugin release still emits the same shape.

    Please report this to the plugin's maintainers. Disabling the plugin, or starting a new session, avoids it.

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