[lambda_http] Fallible response body panics during buffered conversion instead of propagating the body error

Open
#1,165 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
3/5
Estimated time
1-2 days
Newbie friendliness
74/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
rust
Domain
api, backend

Research direction

Start in lambda-http/src/response.rs by reading convert_to_binary and convert_to_text, focusing on the body.collect() calls and their expect() handling. Run the minimal reproduction with cargo run to observe the panic. Done means a fallible body reports its original error without panicking in either buffered conversion path.

Written by the indexing model from the issue text.

Description

Description

lambda_http accepts response body types whose HttpBody::Error is fallible, but the buffered response conversion calls expect() when collecting the body.

If the body returns an error—for example, when a proxied HTTP/1.1 chunked response is truncated—IntoResponse::into_response() panics instead of propagating the body error. This affects both the text and binary conversion paths.

When the handler runs under lambda_http::run, the panic may be caught by lambda_runtime's CatchPanicService and reported as an invocation error, so the process can survive when built with the default panic = "unwind" strategy.

However, this relies on catch_unwind as the error channel instead of propagating the body error:

  • With panic = "abort", which may be used for size-optimized Lambda builds, the process terminates.
  • The diagnostic says that the user handler panicked even though the panic originates inside lambda_http.
  • The structured body error is flattened into a panic message.
  • Outside lambda_http::run, such as in custom runtimes, tests, or other adapters, calling IntoResponse::into_response() directly panics the process, as demonstrated below.

Versions

  • lambda_http: 1.3.0
  • No modifications to lambda_http
  • The same behavior is present in earlier releases
  • rustc: 1.88.0 (6b00bc388 2025-06-23)
  • cargo: 1.88.0 (873a06493 2025-05-10)
  • OS: Debian GNU/Linux 12 (bookworm)
  • Architecture: aarch64
  • Reproduction environment: official rust:1.88-bookworm Docker image

Minimal reproduction

Cargo.toml:

[package]
name = "lambda-http-body-error-repro"
version = "0.1.0"
edition = "2021"

[dependencies]
lambda_http = "=1.3.0"
bytes = "1"
futures-util = "0.3"
http-body = "1"
http-body-util = "0.1"
tokio = { version = "1", features = ["macros", "rt"] }

src/main.rs:

use bytes::Bytes;
use futures_util::stream;
use http_body::Frame;
use http_body_util::StreamBody;
use lambda_http::{IntoResponse, Response};
use std::io::{self, ErrorKind};

#[tokio::main(flavor = "current_thread")]
async fn main() {
    let frames = vec![
        Ok(Frame::data(Bytes::from_static(b"partial response"))),
        Err(io::Error::new(
            ErrorKind::UnexpectedEof,
            "simulated truncated response body",
        )),
    ];
    let body = StreamBody::new(stream::iter(frames));

    let response = Response::builder()
        .header("content-type", "text/plain; charset=utf-8")
        .body(body)
        .unwrap();

    // Panics in lambda_http::response::convert_to_text().
    let _ = response.into_response().await;
}

Run:

cargo run

Actual behavior

The process exits with status 101 and produces the following panic:

thread 'main' panicked at /usr/local/cargo/registry/src/index.crates.io-1949cf8c6b5b557f/lambda_http-1.3.0/src/response.rs:412:42:
unable to read bytes from body: Custom { kind: UnexpectedEof, error: "simulated truncated response body" }
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

A real transport-level example is an HTTP proxy returning a Response<hyper::body::Incoming> where the upstream server closes an HTTP/1.1 chunked response before completing the current chunk.

Hyper exposes the premature closure as a body error. That error reaches the same expect() call in the buffered response conversion and is converted into a panic.

Expected behavior

A response body error should be propagated as an error rather than surfaced through panic! and catch_unwind, so that:

  • the failure is reported as an invocation error regardless of the configured panic strategy;
  • the original body error is preserved in the diagnostic instead of being flattened into a panic message attributed to the user handler;
  • callers of IntoResponse outside lambda_http::run are not taken down by a request-level I/O failure.

If the existing IntoResponse API cannot propagate the error without an API change, returning a deterministic error response from the conversion would still be preferable to panicking.

Affected code

ConvertBody explicitly accepts fallible body types, with bounds including:

B: HttpBody + Unpin + Send + 'static,
B::Data: Send,
B::Error: fmt::Debug,

However, both buffered conversion paths use expect():

body.collect()
    .await
    .expect("unable to read bytes from body")

Source at the lambda_http-v1.3.0 tag:

Impact

A single malformed or prematurely closed upstream response turns a request-level I/O failure into a panic inside the runtime's response conversion path.

This is especially relevant for HTTP adapters and reverse proxies that return a live, fallible HttpBody, because transport-level failures are expected to be represented and handled as normal body errors.

In environments using panic = "abort", this can also terminate the runtime process instead of failing only the affected invocation.

Related issue

This appears to be different from #1051.

That issue concerns an early client closure in the streaming runtime path involving lambda_runtime and send_data().unwrap() under local Lambda emulation.

This report concerns lambda_http::IntoResponse collecting a fallible application response body in the buffered conversion path.

The minimal reproduction does not require:

  • Lambda response streaming;
  • a client disconnect;
  • a Lambda emulator;
  • an actual HTTP server.

It only requires a valid HttpBody implementation that returns an error while its frames are being collected.

Dominant language
Rust
Stars
3.6k
Forks
397
Avg merge
55m
Merged PRs (30d)
1

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from aws/aws-lambda-rust-runtime

All issues in aws/aws-lambda-rust-runtime

Similar issues

More Rust issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.