tokio-rs/tokio · error
filled overflow
Error message
filled overflow
What it means
ReadBuf::advance computes self.filled.checked_add(n).expect('filled overflow'). It panics if advancing the filled region by n would overflow usize — almost always because n is huge (garbage) or the filled counter was already corrupted. set_filled(new) then enforces filled <= initialized.
Source
Thrown at tokio/src/io/read_buf.rs:203
/// Clears the buffer, resetting the filled region to empty.
///
/// The number of initialized bytes is not changed, and the contents of the buffer are not modified.
#[inline]
pub fn clear(&mut self) {
self.filled = 0;
}
/// Advances the size of the filled region of the buffer.
///
/// The number of initialized bytes is not changed.
///
/// # Panics
///
/// Panics if the filled region of the buffer would become larger than the initialized region.
#[inline]
#[track_caller]
pub fn advance(&mut self, n: usize) {
let new = self.filled.checked_add(n).expect("filled overflow");
self.set_filled(new);
}
/// Sets the size of the filled region of the buffer.
///
/// The number of initialized bytes is not changed.
///
/// Note that this can be used to *shrink* the filled region of the buffer in addition to growing it (for
/// example, by a `AsyncRead` implementation that compresses data in-place).
///
/// # Panics
///
/// Panics if the filled region of the buffer would become larger than the initialized region.
#[inline]
#[track_caller]
pub fn set_filled(&mut self, n: usize) {
assert!(
n <= self.initialized,View on GitHub (pinned to 625954f365)
Solutions
- Pass exactly the number of bytes newly written into the buffer (e.g. res from read).
- Validate n <= buf.remaining() / initialized region before calling advance.
- Use ReadBuf helpers (put_slice, put_u8, etc.) which manage filled correctly.
- Add assertions/debug logging of n in your AsyncRead impl to catch corruption early.
Example fix
// before let n = read(&mut buf[written..])?; read_buf.advance(buf.len()); // wrong: full length, overflow risk // after let n = read(&mut buf[written..])?; read_buf.advance(n); // only bytes actually read
Defensive patterns
Strategy: validation
Validate before calling
// Validate n against the buffer's capacity before advancing: let n = read(&mut buf[..])?; assert!(n <= read_buf.remaining(), "advance too large"); read_buf.advance(n);
Type guard
fn safe_advance(buf: &mut tokio::io::ReadBuf<'_>, n: usize) -> Result<(), io::Error> {
if n > buf.remaining() {
return Err(io::Error::new(io::ErrorKind::InvalidInput, "advance exceeds remaining"));
}
buf.advance(n);
Ok(())
} Try / catch
// Use catch_unwind if you cannot trust the upstream AsyncRead:
std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
read_buf.advance(n);
})) Prevention
- Pass only the bytes actually read (the return value of read).
- Use ReadBuf put_* helpers which manage filled correctly.
- Assert n <= buf.remaining() in your AsyncRead impl.
When it happens
Trigger: Calling read_buf.advance(n) with an absurd n (e.g. result of a buggy size computation, or passing bytes_read from a failed read); double-counting bytes already accounted for.
Common situations: AsyncRead impl that advances by the buffer length instead of the bytes actually read; passing buf.remaining() instead of n; integer underflow producing wraparound then overflow; off-by-one in a parser.
Related errors
- early eof
- stream did not contain valid UTF-8
- there is no signal driver running, must be called from the c
- failed to write the buffered data
- write zero byte into writer
AI-assisted analysis of tokio-rs/tokio@625954f365 (2026-08-11).
Data as JSON: /api/errors/4e061bf36d64adf2.
Report an issue: GitHub.