pydantic/monty · info

reduced below 2**32

Error message

reduced below 2**32

What it means

Internal `expect` in `wrapping_u32`: for plain ints the seed is reduced with `rem_euclid(2**32)` before `u32::try_from`, so the conversion is guaranteed to succeed. This mirrors CPython's behaviour of accepting out-of-range CRC seeds by wrapping modulo 2**32 rather than raising. Users passing huge or negative seeds get correct wrapped results, never this panic.

Source

Thrown at crates/monty/src/modules/binascii.rs:406

}

/// Argument shape for `a2b_qp(data, header=False)`.
#[derive(FromArgs)]
#[from_args(name = "a2b_qp", style = c_named, at_most_total)]
struct A2bQpArgs {
    data: Value,
    #[from_args(default = Value::Bool(false))]
    header: Value,
}

/// Reduces an `int` to the `unsigned int` CPython's `I` format takes, which
/// wraps modulo 2**32 rather than rejecting a value out of range — so a
/// negative or huge `crc` seed is accepted, as CPython accepts it.
fn wrapping_u32(value: &Value, vm: &VM<'_>) -> RunResult<u32> {
    const MODULUS: i64 = 1 << 32;

    match value {
        Value::Int(int) => Ok(u32::try_from(int.rem_euclid(MODULUS)).expect("reduced below 2**32")),
        Value::Bool(flag) => Ok(u32::from(*flag)),
        Value::Ref(heap_id) => match vm.heap.get(*heap_id) {
            HeapData::LongInt(long) => {
                // `&` on a `BigInt` is two's-complement, so this is Python's
                // own `value & 0xffffffff` for negatives as well.
                Ok((&long.0 & BigInt::from(u32::MAX)).to_u32().expect("masked below 2**32"))
            }
            _ => Err(ExcType::type_error_not_integer(&value.py_type_name(vm))),
        },
        _ => Err(ExcType::type_error_not_integer(&value.py_type_name(vm))),
    }
}

/// Encodes bytes as lowercase hex, inserting `sep` every `bytes_per_sep` bytes.
///
/// A positive `bytes_per_sep` groups from the right, so any short group leads;
/// a negative one groups from the left. Zero, or no separator, means none.
fn hex_encode(data: &[u8], sep: Option<u8>, bytes_per_sep: i32) -> Vec<u8> {

View on GitHub (pinned to adc986b362)

Solutions

  1. No runtime mitigation; keep the modulo-2**32 reduction ahead of the conversion.
Defensive patterns

Strategy: validation

Prevention

When it happens

Trigger: Unreachable from `binascii.crc32`/`crc_hqx` with any `int` input; would only fire if the `rem_euclid(MODULUS)` reduction were removed.

Common situations: Contributor-only; e.g. someone replacing `rem_euclid` with a direct `try_from`.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of pydantic/monty@adc986b362 (2026-09-13). Data as JSON: /api/errors/faf614778e7ee930. Report an issue: GitHub.