From c9a911b7999de50e9e5023942ca072e9725ae943 Mon Sep 17 00:00:00 2001 From: Nanasi <71248588+spellsaif@users.noreply.github.com> Date: Wed, 5 Aug 2026 07:53:23 -0400 Subject: [PATCH] axum-core: fix nested error downcast (#3858) --- axum-core/src/extract/rejection.rs | 24 +++++++++++++----------- axum/src/routing/tests/mod.rs | 25 +++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/axum-core/src/extract/rejection.rs b/axum-core/src/extract/rejection.rs index ef71cae5..6a1f90f0 100644 --- a/axum-core/src/extract/rejection.rs +++ b/axum-core/src/extract/rejection.rs @@ -19,17 +19,19 @@ impl FailedToBufferBody { where E: Into, { - // two layers of boxes here because `with_limited_body` - // wraps the `http_body_util::Limited` in an `axum_core::Body` - // which also wraps the error type - let box_error = match err.into().downcast::() { - Ok(err) => err.into_inner(), - Err(err) => err, - }; - let box_error = match box_error.downcast::() { - Ok(err) => err.into_inner(), - Err(err) => err, - }; + // peel any number of `axum_core::Error` wrappers to reach the underlying source error + let mut box_error = err.into(); + loop { + match box_error.downcast::() { + Ok(unwrapped) => { + box_error = unwrapped.into_inner(); + } + Err(err) => { + box_error = err; + break; + } + } + } match box_error.downcast::() { Ok(err) => Self::LengthLimitError(LengthLimitError::from_err(err)), Err(err) => Self::UnknownBodyError(UnknownBodyError::from_err(err)), diff --git a/axum/src/routing/tests/mod.rs b/axum/src/routing/tests/mod.rs index 20077a0b..81062aa4 100644 --- a/axum/src/routing/tests/mod.rs +++ b/axum/src/routing/tests/mod.rs @@ -1352,3 +1352,28 @@ async fn middleware_adding_body() { assert_eq!(res.text().await, "…"); } + +#[crate::test] +async fn nested_body_limit_rejection() { + use crate::{ + extract::Request, + middleware::{self, Next}, + response::Response, + }; + use axum_core::RequestExt; + + async fn limit_middleware(req: Request, next: Next) -> Response { + let req = req.with_limited_body(); + next.run(req).await + } + + let app = Router::new() + .route("/", post(|_: Bytes| async {})) + .layer(middleware::from_fn(limit_middleware)) + .layer(middleware::from_fn(limit_middleware)) + .layer(DefaultBodyLimit::max(2)); + + let client = TestClient::new(app); + let res = client.post("/").body("123").await; + assert_eq!(res.status(), StatusCode::PAYLOAD_TOO_LARGE); +}