pydantic/monty · info
index bounded by alphabet length
Error message
index bounded by alphabet length
What it means
This is an internal Rust `expect` inside `base85_table`, which builds a 256-entry reverse-lookup table for an Ascii85/base85 alphabet. The `expect` fires only if a value produced by enumerating the 85-element alphabet does not fit in a `u8`, which is impossible since 85 < 256. It is an unreachable-safety net, not an error users can provoke through the base64 module API.
Source
Thrown at crates/monty/src/modules/base64.rs:925
})?,
None => 84,
};
acc = acc * 85 + u64::from(value);
}
let word = u32::try_from(acc)
.map_err(|_| codec_value_error(format!("{codec} overflow in hunk starting at byte {start}")))?;
out.extend_from_slice(&word.to_be_bytes());
}
out.truncate(out.len() - padding);
Ok(out)
}
/// Reverse lookup for a base85 alphabet: index by byte, `None` outside it.
fn base85_table(alphabet: &[u8; 85]) -> [Option<u8>; 256] {
let mut table = [None; 256];
for (value, byte) in alphabet.iter().enumerate() {
table[usize::from(*byte)] = Some(u8::try_from(value).expect("index bounded by alphabet length"));
}
table
}
/// Encodes bytes as Ascii85, five digits per four-byte word.
///
/// An all-zero word folds to `z` and, with `foldspaces`, four spaces fold to
/// `y`. A short final group is zero-padded to a full word and the digits that
/// padding produced are dropped again unless `pad` is set.
fn a85_encode(data: &[u8], pad: bool, foldspaces: bool) -> Vec<u8> {
let padding = (4 - data.len() % 4) % 4;
let mut out: Vec<u8> = Vec::with_capacity(data.len().div_ceil(4) * 5);
// Where the final word's digits start, so the padding trim below can
// rewrite them the way CPython rewrites `chunks[-1]`.
let mut last_start = 0;
for chunk in data.chunks(4) {
last_start = out.len();View on GitHub (pinned to adc986b362)
Solutions
- Do nothing at runtime; this line cannot fire with the shipped 85-byte alphabets.
- If it fires after your edit, restore the alphabet to exactly 85 unique bytes or change the `Some(u8::try_from(value)...)` conversion to match the new table width.
Defensive patterns
Strategy: validation
Prevention
- Keep base85 alphabets at exactly 85 unique bytes; add a debug assertion or unit test on alphabet length/uniqueness if editing the module.
When it happens
Trigger: Only reachable if a developer edits `base85_table` or an alphabet constant so the alphabet exceeds 256 entries or the enumerate index exceeds 255 — i.e. a source-level change, not any runtime input.
Common situations: Contributors modifying the base85 alphabets (ascii85, RFC 1924, z85) or refactoring the table construction; end users never hit it.
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
- 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
- Undefined found while converting to MontyObject
AI-assisted analysis of pydantic/monty@adc986b362 (2026-09-13).
Data as JSON: /api/errors/b4adc5aa5745a7ab.
Report an issue: GitHub.