Pumpkin-MC/Pumpkin · error

slots_len exceeds limit

Error message

slots_len exceeds limit

What it means

Thrown while decoding legacy inventory slots in the Bedrock PlayerAuthInput packet when the declared slots length exceeds 1024. The limit stops untrusted input from forcing huge allocations or long parse loops.

Solutions

  1. Verify client and server Bedrock protocol versions align
  2. Check network path for corruption/desync
  3. Treat repeat offenders as malicious and disconnect them
  4. Only raise the 1024 limit if a legitimate use case exists
Defensive patterns

Strategy: validation

Validate before calling

let slots_len = VarUInt::read(buf)?.0 as usize;
if slots_len > 1024 { return Err(...); }

Try / catch

if let Err(e) = packet.read(&mut reader) {
    if e.kind() == std::io::ErrorKind::InvalidData { return disconnect(peer); }
    return Err(e.into());
}

Prevention

When it happens

Trigger: PlayerAuthInput with a legacy request id that is < -1 and even, where the subsequent VarUInt slots_len is > 1024.

Common situations: Exploit attempts with inflated length prefixes, protocol version mismatches, or corrupted packet streams.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of Pumpkin-MC/Pumpkin@8d4639e25a (2026-09-09). Data as JSON: /api/errors/cb3c1a9ebb9c2640. Report an issue: GitHub.

Appendix: source

Thrown at crates/pumpkin-protocol/src/bedrock/server/player_auth_input.rs:166

    }
}

#[derive(Debug)]
pub struct PlayerInventoryAction {
    pub legacy_request_id: VarInt,
    pub legacy_slots: Vec<crate::bedrock::server::inventory_transaction::LegacySetItemSlot>,
    pub actions: Vec<crate::bedrock::server::inventory_transaction::InventoryAction>,
    pub transaction: PlayerUseItemTransactionData,
}

impl PacketRead for PlayerInventoryAction {
    fn read<R: Read>(buf: &mut R) -> Result<Self, Error> {
        let legacy_request_id = VarInt::read(buf)?;
        let mut legacy_slots = Vec::new();
        if bool::read(buf)? && legacy_request_id.0 < -1 && (legacy_request_id.0 & 1) == 0 {
            let slots_len = VarUInt::read(buf)?.0 as usize;
            if slots_len > 1024 {
                return Err(Error::new(
                    ErrorKind::InvalidData,
                    "slots_len exceeds limit",
                ));
            }
            legacy_slots.reserve(slots_len.min(64));
            for _ in 0..slots_len {
                legacy_slots.push(
                    crate::bedrock::server::inventory_transaction::LegacySetItemSlot::read(buf)?,
                );
            }
        }
        let mut actions = Vec::new();
        if bool::read(buf)? && bool::read(buf)? {
            let actions_len = VarUInt::read(buf)?.0 as usize;
            if actions_len > 1024 {
                return Err(Error::new(
                    ErrorKind::InvalidData,
                    "actions_len exceeds limit",

View on GitHub (pinned to 8d4639e25a)