formatProviderError function

String formatProviderError(
  1. Object error
)

Composes the display string for an ErrorEvent.errorMessage.

Simplified port of pi's formatProviderError(normalizeProviderError(e)): there is no SDK whose error shapes need probing here.

Implementation

String formatProviderError(Object error) {
  if (error is ProviderHttpError) {
    if (error.answeredHtml) return _formatHtmlAnswer(error);
    if (error.answeredJson) return _formatJsonAnswer(error);
    final redirect = _formatAuthRedirect(error);
    if (redirect != null) return redirect;

    // Issue #867: a structured 429 renders the human message — plan,
    // server-derived reset, next step. The raw payload stays on
    // [RateLimitInfo.rawBody] and never reaches the transcript.
    if (error.rateLimit case final rateLimit?) {
      return '${error.statusCode}: ${formatRateLimitMessage(rateLimit)}';
    }

    final body = error.body.trim();
    if (body.isEmpty) {
      return 'Request failed with status ${error.statusCode}';
    }
    return '${error.statusCode}: $body';
  }
  if (error is http.ClientException) {
    return error.message;
  }
  // Issue #1036 (review round 1): keep the "TimeoutException" word in the
  // rendered text — it IS the contract the model-roles failover chain
  // (`fallback_stream._transportPatterns`) and the providers queue
  // (`providers_queue_runtime._timeoutPatterns`) classify on, routing every
  // watchdog timeout to the retry/failover path. Render the diagnostic
  // message after the keyword, not the exception wrapper's clock noise.
  if (error is TimeoutException) {
    return 'TimeoutException: ${error.message ?? 'provider request timed out'}';
  }
  if (error is StateError) {
    return error.message;
  }
  if (error is FormatException) {
    return error.message;
  }
  return error.toString();
}