Skip to content

tui: provider errors render as unhelpful "Error: Error", hiding the real cause #53602

Open

Description

@jabbas

Summary

When a provider request fails server-side, the TUI session shows a bare Error: Error (generic name + generic message) with no indication of the actual failure type (rate limit, auth, model rejection). The real cause is only visible in the server log, making provider failures undebuggable from the UI.

Environment

  • opencode version: 2.0.22 (homebrew opencode-v2 formula)
  • OS: Darwin 25.5.0 (darwin arm64)
  • Terminal: xterm-kitty (TERM=xterm-kitty, COLORTERM=truecolor)
  • Shell: /bin/zsh
  • Install/channel: latest
  • Active plugins: @andrzejchm/[email protected] (at time of report; also reproduced with a broken/absent auth plugin), local plugins/mnemoteca.js, local plugins/superpowers.js

Reproduction

  1. Configure an anthropic model (e.g. anthropic/claude-opus-5-5) as an agent model.
  2. Trigger any provider-side failure, e.g.:
    • exhaust the Claude Pro/Max rate limit (429), or
    • unload/break the auth plugin so requests fail with an authentication error, or
    • use a model the account cannot access.
  3. Run a prompt in the TUI and wait for the session to fail.

Expected Behavior

The session shows the actual error — e.g. Rate limit exceeded / Authentication failed: ... / the provider's error message — so the user knows what to fix without leaving the UI.

Actual Behavior

The session header shows only:

Error: Error

with no further detail. Two distinct root causes both surfaced as the identical Error: Error:

  • AI.Error.RateLimit (429 from Anthropic) — confirmed in server log as Failed to drain Session ... AI.Error.RateLimit.
  • missing auth for the anthropic provider (auth plugin failed to load with PluginModule.LoadError) — every Claude request failed the same way.

Additional Context

Server log (~/.local/share/opencode/log/opencode.log) for the rate-limit case — note the error message itself is the string Error:

level=ERROR message="Failed to drain Session"
  cause="AI.Error: Error
    at SessionStep.attempt ...
    {
      [cause]: AI.Error.RateLimit: Error
    }"

For comparison, some provider errors do carry a real message and render fine, e.g.:

AI_APICallError: Claude Code 2.1.81 does not support this model; version 2.1.280 or newer is required

Code pointers (checkout at ~/Projects/opencode):

  • packages/tui/src/util/error.ts (errorFormat, line ~110): for Error instances renders error.stack ?? ${error.name}: ${error.message}``; serialized session errors arrive as plain objects and fall through to the JSON path — either way the AI error's cause chain (which holds the real type, e.g. `RateLimit`) is never consulted, so both `name` and `message` render as the literal string `Error`.
  • The swallowing starts server-side: the AI.Error* wrapper in packages/core session execution (Failed to drain Session, packages/core/src/session/execution/local.ts:25) already has message: "Error" with the useful data only in [cause].

Suggested direction: when formatting a failed session error, unwrap cause (and/or include error.type/data) so the failure class and provider message reach the UI; alternatively, preserve the provider message when wrapping into AI.Error.* server-side.

Reproducible: consistently, whenever the provider request fails with an error whose message doesn't survive the AI.Error wrapping (observed on 2026-10-05/06, opencode 2.0.22).

Activity

  1. github-actions commented on Oct 6, 2026

    @github-actions
    Contributor

    This issue might be a duplicate of existing issues. Please check:

    • #36582: broader tracking for making TUI/session API failures explicit and preserving actionable server error details.
  2. opencode-agent commented on Oct 6, 2026

    @opencode-agent
    Contributor

    Thanks for the detailed report. I reproduced this on v2.0.22.

    Steps:

    1. I used a model whose provider request fails with a structured error whose message is just Error, as in your log. I used an authentication_error, since it isn't retried.
    2. I submitted any prompt in the TUI.
    3. The session showed only Error: Error.

    With a descriptive provider message (for example Incorrect API key provided), the TUI shows that text, but it never shows the failure class (Authentication, RateLimit, …). So when the provider's own message is generic, as with the Anthropic 429 you hit, the real cause is hidden. I couldn't test against a real Anthropic rate limit, but the behavior matches what you described.

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

Metadata

Metadata

Assignees

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