cloudflare/pingora · error
must have read body buf
Error message
must have read body buf
What it means
finish_body_buf() is an internal helper of pingora's HTTP/1.1 body reader (protocols/http/v1/body.rs:369): when a body read completes it truncates the shared read buffer and splits off overread bytes, assuming self.body_buf was allocated during reading. The .expect()('must have read body buf') fires when the reader's state machine reaches the finish step with no buffer allocated — an internal invariant violation, not a documented user error.
Source
Thrown at pingora-core/src/protocols/http/v1/body.rs:369
Some(buf) => buf.extend_from_slice(bytes),
None => {
let mut buf = BytesMut::with_capacity(bytes.len());
buf.extend_from_slice(bytes);
self.body_buf_overread = Some(buf);
}
}
}
pub fn body_done(&self) -> bool {
matches!(self.body_state, PS::Complete(_) | PS::Done(_))
}
pub fn body_empty(&self) -> bool {
self.body_state == PS::Complete(0)
}
fn finish_body_buf(&mut self, end_of_body: usize, total_read: usize) {
let body_buf_mut = self.body_buf.as_mut().expect("must have read body buf");
// remove unused buffer
body_buf_mut.truncate(total_read);
let overread_bytes = body_buf_mut.split_off(end_of_body);
self.body_buf_overread = (!overread_bytes.is_empty()).then_some(overread_bytes);
}
pub async fn read_body<S>(&mut self, stream: &mut S) -> Result<Option<BufRef>>
where
S: AsyncRead + Unpin + Send,
{
match self.body_state {
PS::Complete(_) => Ok(None),
PS::Done(_) => Ok(None),
PS::Partial(_, _) => self.do_read_body(stream).await,
PS::Chunked(..) => self.do_read_chunked_body(stream).await,
PS::ChunkedFinal(..) => self.do_read_chunked_body_final(stream).await,
PS::UntilClose(_) => self.do_read_body_until_closed(stream).await,
PS::ToStart => panic!("need to init BodyReader first"),View on GitHub (pinned to 0046038bd4)
Solutions
- Upgrade pingora-core to the latest patch release; invariant panics in the H1 body reader are bug candidates that get fixed
- If it reproduces, capture the exact request/response bytes (pcap or a logging proxy) and open an issue with pingora including the trace
- Audit any custom request/response body filters for reentrant or out-of-order reads of the session body
Example fix
# before: pinned to an older pingora-core with the parser defect pingora-core = "=0.7.0" # after: pick up the fix cargo update -p pingora-core
Defensive patterns
Strategy: try-catch
Try / catch
// Contain H1 body parser panics to a single connection task
let resp = tokio::spawn(async move {
std::panic::catch_unwind(std::panic::AssertUnwindSafe(async {
session.read_body().await // any H1 body read path
}))
.await
.unwrap_or_else(|panic| {
log::error!("H1 body parser panicked: {panic:?}");
Err(internal_error_502())
})
}); Prevention
- Run connection tasks in spawned tasks so a parser panic resets one connection, not the worker
- Fuzz HTTP/1.1 traffic (malformed bodies, zero-length, early close) in CI against your build
- Pin tested pingora-core versions and upgrade promptly when H1 parser fixes ship
- Keep pcaps/request logs on failures so internal panics can be reported with a reproducer
When it happens
Trigger: Any code path that drives Http1Body to body completion without a prior buffered read allocating body_buf — in practice triggered by a pingora bug or by custom filters that reenter/manipulate the downstream or upstream session body state unexpectedly. Surfaces as a panic (502/reset) while proxying an HTTP/1.1 response.
Common situations: Upgrading between pingora versions with parser refactors; unusual HTTP/1.1 traffic (zero-length bodies, early end-of-stream combinations) hitting an untested state; downstream code misusing session body readers concurrently.
Related errors
- body buf exists once a partial chunk head was buffered
- body buf exists once a chunk was parsed out of it
- body buf is initialized before reading trailers
- take_write_lock() called without cache lock
- take_write_lock() called without lock
AI-assisted analysis of cloudflare/pingora@0046038bd4 (2026-08-16).
Data as JSON: /api/errors/a8720bace71a4a1d.
Report an issue: GitHub.