formatProviderError function
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();
}