11use forge_app:: domain:: { Error as DomainError , RetryConfig } ;
2+ use forge_app:: dto:: anthropic:: Error as AnthropicError ;
23use forge_app:: dto:: openai:: { Error , ErrorResponse } ;
34
45const TRANSPORT_ERROR_CODES : [ & str ; 3 ] = [ "ERR_STREAM_PREMATURE_CLOSE" , "ECONNRESET" , "ETIMEDOUT" ] ;
@@ -16,13 +17,22 @@ pub fn into_retry(error: anyhow::Error, retry_config: &RetryConfig) -> anyhow::E
1617 || is_req_transport_error ( & error)
1718 || is_event_transport_error ( & error)
1819 || is_empty_error ( & error)
20+ || is_anthropic_overloaded_error ( & error)
1921 {
2022 return DomainError :: Retryable ( error) . into ( ) ;
2123 }
2224
2325 error
2426}
2527
28+ /// Checks if the error is an Anthropic `overloaded_error`, which arrives as an
29+ /// SSE event payload rather than an HTTP status code and must be retried.
30+ fn is_anthropic_overloaded_error ( error : & anyhow:: Error ) -> bool {
31+ error
32+ . downcast_ref :: < AnthropicError > ( )
33+ . is_some_and ( |e| matches ! ( e, AnthropicError :: OverloadedError { .. } ) )
34+ }
35+
2636fn get_api_status_code ( error : & anyhow:: Error ) -> Option < u16 > {
2737 error. downcast_ref :: < Error > ( ) . and_then ( |error| match error {
2838 Error :: Response ( error) => error
@@ -294,6 +304,21 @@ mod tests {
294304 assert ! ( get_event_req_status_code( & error) . is_none( ) ) ;
295305 }
296306
307+ #[ test]
308+ fn test_anthropic_overloaded_error_is_retryable ( ) {
309+ let retry_config = fixture_retry_config ( vec ! [ ] ) ;
310+
311+ // overloaded_error arriving as an SSE event must be retried
312+ let error = anyhow:: Error :: from ( AnthropicError :: OverloadedError {
313+ message : "Overloaded" . to_string ( ) ,
314+ } ) ;
315+ assert ! ( is_retryable( into_retry( error, & retry_config) ) ) ;
316+
317+ // Generic errors are still not retryable
318+ let error = anyhow ! ( "Generic error" ) ;
319+ assert ! ( !is_retryable( into_retry( error, & retry_config) ) ) ;
320+ }
321+
297322 #[ tokio:: test]
298323 async fn test_incomplete_message_is_retryable ( ) {
299324 use tokio:: net:: TcpListener ;
0 commit comments