astral-sh/ruff · error
Expected live-bindings length to fit into a u32
Error message
Expected live-bindings length to fit into a u32
What it means
InternedBindings::push appends each scope's live bindings to one flat Vec and stores the cumulative end offset, which must fit in u32 because definition IDs are 32-bit. .expect("Expected live-bindings length to fit into a u32") asserts the cumulative total stays below ~4.29 billion - the comment notes a single scope cannot practically approach this limit.
Source
Thrown at crates/ty_python_core/src/use_def.rs:489
struct RetainedBindingsBuilder {
ends: IndexVec<InternedBindingsId, u32>,
live_bindings: Vec<LiveBinding>,
}
impl RetainedBindingsBuilder {
fn with_capacity(bindings: usize) -> Self {
Self {
ends: IndexVec::with_capacity(bindings),
live_bindings: Vec::with_capacity(bindings),
}
}
fn push(&mut self, bindings: &Bindings) -> InternedBindingsId {
// Definition IDs are also 32-bit and a single scope cannot practically approach this
// limit. Keeping one cumulative end offset per state halves the retained range metadata.
self.live_bindings.extend_from_slice(bindings.as_slice());
let end = u32::try_from(self.live_bindings.len())
.expect("Expected live-bindings length to fit into a u32");
self.ends.push(end)
}
fn get(&self, index: InternedBindingsId) -> &[LiveBinding] {
let end = self.ends[index];
let start = if index.index() == 0 {
0
} else {
self.ends[InternedBindingsId::new(index.index() - 1)]
};
&self.live_bindings[start as usize..end as usize]
}
fn finish(
self,
narrowing_constraints: &mut NarrowingConstraintsBuilder,
reachability_constraints: &mut ReachabilityConstraintsBuilder,
) -> RetainedBindings {View on GitHub (pinned to 15f3fe6b15)
Solutions
- Not fixable from the caller side; if it fires, preserve the input and report it upstream
- Cap generated-input sizes in fuzzing harnesses
- If interning externally generated data, keep per-run scopes bounded so cumulative counts stay orders of magnitude below u32::MAX
Defensive patterns
Strategy: validation
Validate before calling
// fuzz harnesses: cap bindings per run far below u32::MAX
if total_bindings > 100_000_000 { return; } // abandon pathological inputs Try / catch
let ok = std::panic::catch_unwind(|| intern_bindings(&scopes)); // isolate in long-running tools
Prevention
- Cap generated input sizes in fuzzers
- Treat this expect as unreachable-by-design; a repro is an upstream bug report
- Avoid interning unbounded externally generated binding sets in one run
When it happens
Trigger: Interning bindings until total live-binding entries exceed u32::MAX - requires billions of definitions across one interned set, far beyond real Python code; effectively only reachable via adversarial or machine-generated input.
Common situations: Fuzzers or code generators emitting pathological binding counts; not observed with human-scale codebases.
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
- expected class
- expected function
- expected type alias
- i is bounded by INLINE_MAX_SEGMENTS
- index is bounded by INLINE_MAX_SEGMENTS
AI-assisted analysis of astral-sh/ruff@15f3fe6b15 (2026-08-20).
Data as JSON: /api/errors/519a0f6a175a6aef.
Report an issue: GitHub.