pydantic/monty · info

masked below 2**32

Error message

masked below 2**32

What it means

Internal `expect` in `wrapping_u32` for arbitrary-precision (`LongInt`) seeds: the BigInt is bitwise-ANDed with `0xffffffff`, so the result fits a `u32` and `to_u32()` cannot return `None`. The two's-complement `&` reproduces Python's `value & 0xffffffff` for negatives. Not user-triggerable from `crc32`/`crc_hqx`.

Solutions

  1. No runtime action; preserve the `& 0xffffffff` masking before `to_u32()`.
Defensive patterns

Strategy: validation

Prevention

When it happens

Trigger: Unreachable; requires the mask (`& BigInt::from(u32::MAX)`) to be removed or changed in a code edit.

Common situations: Only during refactors of the bigint seed path in `wrapping_u32`.

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

Appendix: source

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

    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> {
    let group = match sep {
        Some(_) if bytes_per_sep != 0 && !data.is_empty() => usize::try_from(bytes_per_sep.unsigned_abs())
            .expect("u32 fits usize on supported targets")
            .min(data.len()),
        // Without a separator, or with an empty input, emit one flat run.
        _ => data.len().max(1),

View on GitHub (pinned to adc986b362)