Skip to content

Streaming response validation fails when provider returns empty delta.role instead of "assistant" #28427

@timxx

Description

@timxx

Description

Bug description

When using a custom openai compat server, opencode fails during streaming response parsing if the model server returns an empty string for choices[0].delta.role.

It looks like opencode strictly validates the streaming chunk and requires:

"role": "assistant"

But some providers/model servers return:

"role": ""

This causes a AI_TypeValidationError / ZodError, and the stream processing fails.

Actual behavior

opencode throws a validation error like:

AI_TypeValidationError: Type validation failed
Invalid input: expected "assistant"
path: choices[0].delta.role

Relevant log excerpt:

ERROR service=llm providerID=corenet modelID=zhipu/glm-5 ... error={"error":{"name":"AI_TypeValidationError","cause":{"name":"ZodError","message":"[
  {
    "code": "invalid_union",
    "errors": [
      [
        {
          "code": "invalid_value",
          "values": [
            "assistant"
          ],
          "path": [
            "choices",
            0,
            "delta",
            "role"
          ],
          "message": "Invalid input: expected \"assistant\""
        }
      ],
      [
        {
          "expected": "object",
          "code": "invalid_type",
          "path": [
            "error"
          ],
          "message": "Invalid input: expected object, received undefined"
        }
      ]
    ],
    "path": [],
    "message": "Invalid input"
  }
]"},"value":{"choices":[{"index":0,"delta":{"role":"","content":"**","reasoning_content":""}}],"created":1779246053,"id":"270bc6e14cb74c75a0f10e2d23e03680","model":"glm-5","object":"chat.completion.chunk","usage":{"prompt_tokens":0,"completion_tokens":0,"total_tokens":0,"prompt_tokens_details":{}}}}} stream error

Another example chunk from the same stream:

{
  "choices": [
    {
      "index": 0,
      "delta": {
        "role": "",
        "content": "Local",
        "reasoning_content": ""
      }
    }
  ],
  "created": 1779246053,
  "id": "270bc6e14cb74c75a0f10e2d23e03680",
  "model": "glm-5",
  "object": "chat.completion.chunk",
  "usage": {
    "prompt_tokens": 0,
    "completion_tokens": 0,
    "total_tokens": 0,
    "prompt_tokens_details": {}
  }
}

Expected behavior

opencode should tolerate providers that return an empty or missing delta.role in streaming chunks.

Possible ways to handle this:

  • treat empty role as "assistant" for assistant message streams, or
  • allow role to be empty/missing on subsequent chunks, or
  • normalize provider responses before Zod validation

Why this seems to be an opencode compatibility issue

Some model servers do not strictly follow the expected streaming schema and may emit role: "" instead of "assistant".

Even if the upstream provider behavior is imperfect, opencode could be more robust here, since the rest of the chunk is valid and usable.

Plugins

No response

OpenCode version

1.15.5

Steps to reproduce

A provider-specific setup is not required. This can be reproduced with any mock or proxy that returns OpenAI-compatible streaming chunks with an empty delta.role.

Minimal reproduction idea

Configure opencode against a local/mock OpenAI-compatible endpoint and return a streaming SSE response containing a chunk like:

{
  "choices": [
    {
      "index": 0,
      "delta": {
        "role": "",
        "content": "hello"
      }
    }
  ],
  "created": 1779246053,
  "id": "example_chunk_id",
  "model": "test-model",
  "object": "chat.completion.chunk"
}

Then observe that opencode fails with a type validation error.

Reproduction outline

  1. Run any local mock server that exposes an OpenAI-compatible chat/completions streaming endpoint
  2. Configure opencode to use that endpoint
  3. Start a streamed chat request
  4. Have the mock server emit an SSE chunk where:
    "choices": [
      {
        "delta": {
          "role": "",
          "content": "hello"
        }
      }
    ]
  5. Observe stream failure with AI_TypeValidationError

Screenshot and/or share link

No response

Operating System

Windows 11

Terminal

nushell

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions