Skip to content

fix(runtime): derive provider error reason and message from one classification #1074

Description

@Astro-Han

Problem

A structured provider stream failure can be classified correctly by the runtime while still producing the generic visible message Operation failed.

Observed in a Maka CLI session using Ollama Cloud with GLM-5.2:

  • Four runs ended with failureClass: "network".
  • All four persisted failureMessage: "Operation failed".
  • The CLI faithfully rendered the runtime error event; the actionable category had already been lost before reaching the CLI projection.

This produces a contradictory error projection:

reason: network
message: Operation failed

Root cause

ModelAdapter.makeErrorEvent() currently derives the machine-readable reason and user-visible message through different paths:

const message = generalizedErrorMessage(err);
const reason = errorReasonFromClass(classifyError(err));

classifyError() normalizes structured provider error objects and serializes their nested evidence, so an object containing fetch or network is correctly classified as Network.

generalizedErrorMessage() uses String(error) for non-Error values. A structured provider object therefore becomes [object Object], misses every category, and falls back to Operation failed.

The provider classification is already the authoritative fact. The visible message should be derived from that same classification rather than independently parsing the raw value again.

Desired outcome

A provider error is classified once at the runtime boundary, and both its machine-readable reason and safe user-visible message are derived from that classification.

For a structured network error, the emitted event must contain:

reason: network
message: Network error

Proposed seam

  • Add a pure safe-message mapping next to the existing provider error classification helpers.
  • In ModelAdapter.makeErrorEvent(), call classifyError() once.
  • Derive both reason and message from the resulting class.
  • Stop using generalizedErrorMessage() for provider error events.
  • Keep generic UI error handling unchanged.

If a second caller later needs the complete class/reason/message/code projection, the helpers can be combined into a first-class projectProviderError() API then. This issue does not require that broader abstraction.

Acceptance criteria

  • A structured provider object containing network evidence emits:
    • reason: "network"
    • message: "Network error"
  • reason and message cannot describe different provider error categories.
  • Existing Error and string provider inputs retain their safe categorized messages.
  • Raw provider messages and secrets are not exposed in visible events.
  • Unknown provider errors still fall back to Operation failed.
  • Unit tests cover structured object, Error, and string inputs.

Non-goals

  • Changing retry policy.
  • Retrying after partial model output.
  • Adding attempt supersession semantics.
  • Exposing raw provider error bodies.
  • Refactoring generic Desktop/UI error presentation.
  • Migrating telemetry and trace APIs to a new projection type.

Activity

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

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions