Pumpkin-MC/Pumpkin · error · AdvancementDataError

JSON error

Error message

JSON error: {0}

What it means

PacketDecodeError::OutOfBounds is raised when the declared packet length is not within the valid bounds for decoding — typically a negative value, zero where data is required, or a length inconsistent with the remaining bytes in the buffer. The library validates the length before consuming the payload. It guards the decoder against impossible framing.

Solutions

  1. Check that the full packet body is buffered before decoding (read length, then wait for len bytes).
  2. Verify the connection was not closed/truncated mid-packet before interpreting the error.
  3. Treat the peer as misbehaving and close the connection; framing cannot be trusted after OutOfBounds.
  4. If parsing a captured/external byte stream, validate the length against buffer size before calling decode.

Example fix

// before
let body = reader.read_exact(len as usize).await?; // len may exceed available bytes
// after
if len < 0 || len as usize > reader.remaining() {
    return Err(PacketDecodeError::OutOfBounds);
}
let body = reader.read_exact(len as usize).await?;
Defensive patterns

Strategy: validation

Validate before calling

fn in_bounds(len: i32, available: usize) -> bool {
    len > 0 && (len as usize) <= available
}

Type guard

fn is_in_bounds(len: i64, available: usize) -> bool {
    len > 0 && len <= available as i64
}

Try / catch

match decode_packet(stream).await {
    Err(PacketDecodeError::OutOfBounds) => { warn!("bad packet framing; closing connection"); break; }
    Ok(p) => handle(p),
    Err(e) => warn!("decode error: {e}"),
}

Prevention

When it happens

Trigger: Decoding a packet whose length VarInt decodes to a negative or otherwise invalid value; the declared length exceeds the bytes actually available in the read buffer.

Common situations: A truncated read (connection cut mid-packet) leaving fewer bytes than the declared length; corrupted or attacker-supplied length fields; a buggy client implementation producing malformed framing.

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

Appendix: source

Thrown at crates/pumpkin/src/entity/player/advancement.rs:247

    #[must_use]
    pub(crate) const fn awarded(self) -> bool {
        self.awarded
    }

    pub(crate) const fn combine(self, other: Self) -> Self {
        Self {
            awarded: self.awarded || other.awarded,
            completed: self.completed || other.completed,
        }
    }
}

/// Errors that can occur when saving or loading advancement data.
#[derive(Debug, thiserror::Error)]
pub enum AdvancementDataError {
    #[error("IO error: {0}")]
    Io(std::io::Error),
    #[error("JSON error: {0}")]
    Json(serde_json::Error),
}

impl PlayerAdvancement {
    /// Creates a new instance of `PlayerAdvancement`.
    #[must_use]
    pub fn new(manager: Arc<AdvancementManager>, uuid: Uuid) -> Self {
        Self {
            progress: AdvancementProgressMap::default(),
            path: manager.advancement_path.join(format!("{uuid}.json")),
            manager,
            player: Weak::new(),
            is_first_packet: true,
            roots_to_update: HashSet::default(),
            visible: HashSet::default(),
            progress_changed: HashSet::default(),
            last_selected_tab: None,
        }

View on GitHub (pinned to 8d4639e25a)