rustfs/rustfs · warning · io::Error

invalid number of entries

Error message

invalid number of entries

What it means

The entry count must be between 0 and 65536 inclusive (MAX_INDEX_ENTRIES = 1<<16). load rejects negative or oversized counts with InvalidData before allocating the info vector, which also guards against absurd allocations driven by corrupt counts.

Source

Thrown at crates/rio-v2/src/s2_index.rs:205

        let (total_uncompressed, used) = read_varint(bytes)?;
        if total_uncompressed < 0 {
            return Err(io::Error::new(io::ErrorKind::InvalidData, "invalid uncompressed size"));
        }
        bytes = &bytes[used..];

        let (total_compressed, used) = read_varint(bytes)?;
        bytes = &bytes[used..];

        let (est_block_uncompressed, used) = read_varint(bytes)?;
        if est_block_uncompressed < 0 {
            return Err(io::Error::new(io::ErrorKind::InvalidData, "invalid block size"));
        }
        bytes = &bytes[used..];

        let (entries, used) = read_varint(bytes)?;
        if entries < 0 || entries > MAX_INDEX_ENTRIES as i64 {
            return Err(io::Error::new(io::ErrorKind::InvalidData, "invalid number of entries"));
        }
        bytes = &bytes[used..];

        if bytes.is_empty() {
            return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "buffer too small"));
        }

        let has_uncompressed = bytes[0];
        if has_uncompressed & 1 != has_uncompressed {
            return Err(io::Error::new(io::ErrorKind::InvalidData, "invalid uncompressed flag"));
        }
        bytes = &bytes[1..];

        let mut info = vec![
            S2IndexInfo {
                compressed_offset: 0,
                uncompressed_offset: 0,
            };

View on GitHub (pinned to 9e6e02ea09)

Solutions

  1. Fall back to no-index reads.
  2. If more than 65536 blocks are genuinely required, raise MAX_INDEX_ENTRIES deliberately and simultaneously in writer and reader — they must agree.
  3. Alternatively re-compress with a larger block size so the entry count stays under the cap.
Defensive patterns

Strategy: fallback

Validate before calling

fn entry_count_plausible(entries: i64) -> bool {
    (0..=(1 << 16)).contains(&entries)
}

Try / catch

match decode_minio_index_bytes(&bytes) {
    Some(index) => use_index(index),
    None => sequential_decompress(),
}

Prevention

When it happens

Trigger: A corrupted count varint decoding to a huge or negative i64; an index written by a non-conforming writer with more than 65536 blocks.

Common situations: Corruption class; extremely large objects compressed with very small block sizes legitimately exceeding the entry cap.

Related errors


AI-assisted analysis of rustfs/rustfs@9e6e02ea09 (2026-08-16). Data as JSON: /api/errors/72729396fdf6b661. Report an issue: GitHub.