From bb0da5feb300cb8335c98ca3748dc3559594496f Mon Sep 17 00:00:00 2001 From: mateo-berri <277851410+mateo-berri@users.noreply.github.com> Date: Sat, 7 Nov 2026 16:52:42 -0800 Subject: [PATCH] fix(router): answer a context window error when the request num_retries cannot be read A request num_retries the retry loop cannot compare raised the loop's TypeError as a 500 once a context window error became retryable. Hand the context window error on instead, as the request got before. --- litellm-rust/crates/router-core/src/call.rs | 7 ++++-- .../crates/router-core/tests/call_loop.rs | 23 +++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/litellm-rust/crates/router-core/src/call.rs b/litellm-rust/crates/router-core/src/call.rs index 2dd95df9705..d6975baac3b 100644 --- a/litellm-rust/crates/router-core/src/call.rs +++ b/litellm-rust/crates/router-core/src/call.rs @@ -1098,17 +1098,20 @@ impl Core { }); } if uncounted == Some(UncountedRetries::Raises) { + if let Some(refusal) = refusal { + return Err(refusal); + } self.host.observe(&RouterEvent::RetryCountRaised { level: at.level, model: target.group.clone(), cause: RetryCause::of(&failed.error), }); - return Err(refusal.unwrap_or(Failed { + return Err(Failed { error: Box::new(Error::Attempt(AttemptError::host_raised(&["Exception"]))), deployment_id: None, routed: None, served_as: None, - })); + }); } if num_retries == 0 { return Err(refusal.unwrap_or(failed)); diff --git a/litellm-rust/crates/router-core/tests/call_loop.rs b/litellm-rust/crates/router-core/tests/call_loop.rs index 1870bb8f956..86012e1bfbd 100644 --- a/litellm-rust/crates/router-core/tests/call_loop.rs +++ b/litellm-rust/crates/router-core/tests/call_loop.rs @@ -1106,6 +1106,29 @@ async fn a_retry_that_fails_after_a_context_window_error_raises_that_error(confi assert_eq!(host.selected().len(), 3); } +#[rstest] +#[tokio::test] +async fn a_num_retries_that_raises_leaves_a_context_window_error_standing(config: RouterConfig) { + let host = Arc::new(ScriptedHost::failing("primary", vec![context_window()])); + let router = router(config, json!({"num_retries": 2}), host.clone()); + let request = RouterRequest { + uncounted_retries: Some(UncountedRetries::Raises), + ..request() + }; + let refused = router.call(Op::from("acompletion"), request).await; + assert!( + matches!(refused, Err(Error::Attempt(failed)) if failed.kind == FailureKind::ContextWindowExceeded) + ); + assert!( + !host + .events + .lock() + .iter() + .any(|event| matches!(event, RouterEvent::RetryCountRaised { .. })) + ); + assert_eq!(host.selected().len(), 1); +} + #[rstest] #[tokio::test] async fn a_failed_agentic_followup_is_not_retried_but_still_falls_back(config: RouterConfig) {