Skip to content

Wrapped stream error chunks bypass retry and can leave parent sessions waiting forever #21979

@tossp

Description

@tossp

Description

When a provider using the Responses streaming path returns a wrapped error chunk such as:

{"error":{"code":"","message":"","type":"server_error"},"request_id":""}

OpenCode currently tries to validate it as a normal response.* stream event and fails with:

  • Type validation failed
  • invalid_union

This appears to happen before any terminal event like response.completed / response.incomplete is seen.

That makes the failure behave like a stream protocol failure before terminal event, but it is currently surfaced as a schema/type validation error instead of a retryable API/stream failure.

This is especially problematic for subagents/background tasks: the child stream can die without entering a proper terminal failed/completed state, while the parent keeps waiting for the child response indefinitely.

Based on local investigation:

  • the Responses path only treats response.completed / response.incomplete as terminal
  • wrapped error chunks are not normalized before schema validation
  • existing retry/backoff is already wired for APICallError -> MessageV2.APIError -> SessionRetry.retryable()
  • plugin hooks can modify request params/headers, but cannot intercept/normalize response stream chunks before validation

So the current behavior seems to be:

  1. provider sends wrapped error chunk in stream
  2. chunk is validated as normal response.* event
  3. union validation fails (invalid_union)
  4. failure does not enter the normal retryable API error path
  5. parent/subagent waiting logic may never get a proper terminal failure signal

Plugins

oh-my-opencode

OpenCode version

Observed on recent OpenCode builds using the Responses streaming path; local repo analysis was against anomalyco/opencode dev and a local installation that surfaced the bundled stack in the TUI worker.

Steps to reproduce

  1. Use a provider/model path that goes through the Responses streaming implementation.
  2. Have the upstream stream return a wrapped error chunk like:
{"error":{"code":"","message":"","type":"server_error"},"request_id":""}
  1. Observe that OpenCode reports a Type validation failed / invalid_union error instead of handling it like a retryable stream/API failure.
  2. In subagent/background-task scenarios, observe that the parent can continue waiting because the child did not complete with a normal terminal event.

Screenshot and/or share link

Example error payload observed locally:

Type validation failed: Value: {"error":{"code":"","message":"","type":"server_error"},"request_id":""}
Error message: invalid_union ...

Operating System

Linux

Terminal

N/A


Expected behavior

Wrapped stream error chunks / premature stream failures before response.completed or response.incomplete should be treated as something like:

  • stream terminated before terminal event
  • or stream ended without completed response

and then mapped into the existing retry/backoff flow (for example via APICallError with the correct retryability), instead of surfacing as raw schema validation failure.

That would make this behave more like retryable HTTP/provider failures and also ensure parent sessions/subagents receive a proper terminal failure signal.

Suggested direction

For the Responses streaming path:

  • skip empty/meta-only frames
  • detect wrapped error chunks such as { "error": { ... } }
  • normalize them before schema validation, or convert them directly into a retryable APICallError
  • if the stream ends without response.completed / response.incomplete, treat that as a stream termination failure rather than a generic validation error

This would avoid the invalid_union surface error and should also prevent parent agents from waiting forever on failed child streams.

Metadata

Metadata

Assignees

Labels

coreAnything pertaining to core functionality of the application (opencode server stuff)

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