tokio-rs/tokio · error · io::Error

provided length would overflow after adjustment

Error message

provided length would overflow after adjustment

What it means

Runtime error from `LengthDelimitedCodec::decode_head` (length_delimited.rs:547). After applying `length_adjustment` to the raw length-field value, `checked_add`/`checked_sub` returned `None` — the adjusted payload size overflowed `usize`. It indicates a `length_adjustment` configuration that pushes a representable length out of range.

Source

Thrown at tokio-util/src/codec/length_delimited.rs:547

                    LengthDelimitedCodecError { _priv: () },
                ));
            }

            // The check above ensures there is no overflow
            let n = n as usize;

            // Adjust `n` with bounds checking
            let n = if self.builder.length_adjustment < 0 {
                n.checked_sub(-self.builder.length_adjustment as usize)
            } else {
                n.checked_add(self.builder.length_adjustment as usize)
            };

            // Error handling
            match n {
                Some(n) => n,
                None => {
                    return Err(io::Error::new(
                        io::ErrorKind::InvalidInput,
                        "provided length would overflow after adjustment",
                    ));
                }
            }
        };

        src.advance(self.builder.get_num_skip());

        // Ensure that the buffer has enough space to read the incoming
        // payload
        src.reserve(n.saturating_sub(src.len()));

        Ok(Some(n))
    }

    fn decode_data(&self, n: usize, src: &mut BytesMut) -> Option<BytesMut> {
        // At this point, the buffer has already had the required capacity

View on GitHub (pinned to 625954f365)

Solutions

  1. Re-check `length_adjustment` sign and magnitude against the protocol spec (`Builder::length_adjustment`).
  2. Cap the wire length with `max_frame_length` so the adjustment cannot overflow.
  3. Treat this as a configuration bug — fix the codec builder rather than handling it per-frame.
  4. Print the builder settings (`length_field_len`, `length_field_offset`, `length_adjustment`, `num_skip`) and compare against the peer.

Example fix

// before: wrong-sign adjustment causes overflow on large frames
let codec = LengthDelimitedCodec::builder()
    .length_adjustment(-i64::MAX)
    .new_codec();

// after: correct adjustment per protocol spec
let codec = LengthDelimitedCodec::builder()
    .length_field_length(4)
    .length_adjustment(0)
    .new_codec();
Defensive patterns

Strategy: validation

Validate before calling

// Sanity-check the adjustment against the length field's representable range
let max_field = (1usize << (length_field_len * 8)) - 1;
debug_assert!(length_adjustment.abs() as u64 <= max_field as u64, "adjustment can overflow the field");

Type guard

fn is_length_overflow(e: &io::Error) -> bool {
    e.kind() == io::ErrorKind::InvalidInput && e.to_string().contains("overflow after adjustment")
}

Try / catch

match framed.next().await {
    Some(Err(e)) if is_length_overflow(&e) => { /* config bug: fix builder, then close */ return Err(anyhow!("length_adjustment misconfigured: {e}")); }
    other => other,
}

Prevention

When it happens

Trigger: A length-field value that is valid on its own but, after the configured add/subtract of `length_adjustment`, exceeds `usize::MAX` or underflows. Almost always a builder misconfiguration rather than a runtime data condition.

Common situations: Wrong sign on `length_adjustment`; an adjustment value near `usize::MAX`; confusing the semantics of `length_adjustment` (it modifies the field-derived length, not `data.len()`).

Related errors


AI-assisted analysis of tokio-rs/tokio@625954f365 (2026-08-11). Data as JSON: /api/errors/8454d16ef48f6390. Report an issue: GitHub.