Skip to content

ai: classify plain AI SDK stream errors #43791

Closed

Description

@rekram1-node

Summary

Plain errors emitted by an AI SDK model stream bypass shared provider-failure classification. Transient messages such as provider capacity errors are therefore classified as UnknownProvider and are not retried, while equivalent APICallError and native AI-package failures use classifyProviderFailure correctly.

Environment

  • opencode version: v0.0.0-dev-17773
  • OS: Darwin 25.6.0 arm64
  • Terminal: Ghostty (TERM=xterm-256color, COLORTERM=truecolor)
  • Shell: /bin/zsh
  • Install/channel: dev, V2
  • Active plugins: none configured

Reproduction

  1. Configure an AI SDK language model whose stream emits an error part containing a plain Error, rather than an APICallError.
  2. Use a transient provider message such as The model is currently at capacity due to high demand. Please try again in a few minutes.
  3. Run a prompt through the V2 Session runner.

Expected Behavior

The plain stream error message should pass through the shared provider-failure classifier. Known transient text should become ProviderInternal and participate in the existing retry policy.

Actual Behavior

packages/core/src/aisdk.ts routes APICallError through RequestExecutor.classifyHttpFailure, which reaches classifyProviderFailure. A plain Error instead falls through llmError() directly to UnknownProviderReason, so transient text matching never runs and the failure is not retried.

Additional Context

This affects AI SDK stream errors from language.doStream(), readable-stream failures, and LanguageModelV3StreamPart error events whenever the underlying value is a plain error. Native AI-package HTTP failures and modeled stream error events already converge on packages/ai/src/provider-error.ts.

The fix should preserve unknown plain errors as UnknownProvider while allowing known structured or textual classifications to use the shared classifier. Add coverage for a plain AI SDK stream error carrying transient capacity text, alongside the existing APICallError tests.

Activity

  1. opencodejr commented on Oct 28, 2026

    @opencodejr
    Contributor

    Thanks for the detailed write-up. I reproduced this on v2.0.0, which has the same llmError() code as your dev build. A plain Error with the capacity text, whether it comes from doStream() rejecting or from a stream error part, was classified as UnknownProvider instead of ProviderInternal. (At that tag SessionRunnerRetry.isRetryable still returned true for it, so I could confirm the wrong classification but not the missing retry.)

    On the latest dev (a882cf9) it no longer happens. llmError() in packages/core/src/aisdk.ts now sends plain errors through RequestExecutor.httpFailure, which calls classifyProviderFailure. The same tests now give ProviderInternal and count as retryable on both paths, and unrecognised plain errors (e.g. Bad Request) still stay UnknownProvider. The change seems to come from #51194 and has been in releases since v2.1.0. One part of your request may still be missing: I didn't find a test for a plain stream error with capacity text in packages/core/test/aisdk.test.ts, so that regression coverage could still be worth adding.

    This looks fixed. The bot will close this issue in 1 day unless you reply that it still happens, e.g. on a newer build.

  2. Tarquinen commented on Nov 2, 2026

    @Tarquinen
    Member

    This was fixed by #51194, which has been in releases since v2.1.0, so I'm closing this issue.

    — from 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊

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