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
- No runtime mitigation; keep the modulo-2**32 reduction ahead of the conversion.
Defensive patterns
Strategy: validation
Prevention
- Reduce with `rem_euclid(2**32)` (not `%`) so negative seeds map into range before `u32::try_from`.
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
- nibble fits usize
- gather commit frame id is not a GatherFuture
- gather item is not a Coroutine, ExternalFuture, or GatherFut
- Cannot get identity of Dereferenced object
- invalid ascii byte
AI-assisted analysis of pydantic/monty@adc986b362 (2026-09-13).
Data as JSON: /api/errors/faf614778e7ee930.
Report an issue: GitHub.