Pumpkin-MC/Pumpkin · error

actions_len exceeds limit

Error message

actions_len exceeds limit

What it means

Hard sanity cap in SPlayerAuthInput's item-use transaction decoding: after reading the two boolean flags and the actions_len VarUInt, values above 1024 are rejected with InvalidData before any allocation loop. The offending input is the actions_len count declared by the client — a malicious or desynchronized client claiming an absurd number of inventory actions; the guard prevents huge pre-reservations and long loops.

Solutions

  1. Drop the offending auth-input packet
  2. Retain the length cap before reserving the vector
  3. Log the oversized actions count at debug level
Defensive patterns

Strategy: validation

Validate before calling

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

Try / catch

if let Err(e) = decode(&buf) {
    if e.kind() == std::io::ErrorKind::InvalidData && e.to_string().contains("exceeds limit") { drop_packet(); }
}

Prevention

When it happens

Trigger: PlayerAuthInput packet where both gating bools are true and the VarUInt actions_len is > 1024.

Common situations: Clients with huge queued transaction batches, buggy client mods, or deliberately crafted oversized packets.

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/1bdb04f6759d534d. Report an issue: GitHub.

Appendix: source

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

            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",
                ));
            }
            actions.reserve(actions_len.min(64));
            for _ in 0..actions_len {
                actions.push(
                    crate::bedrock::server::inventory_transaction::InventoryAction::read(buf)?,
                );
            }
        }
        let transaction = PlayerUseItemTransactionData::read(buf)?;
        Ok(Self {
            legacy_request_id,
            legacy_slots,
            actions,
            transaction,
        })

View on GitHub (pinned to 8d4639e25a)