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

  1. Not fixable from the caller side; if it fires, preserve the input and report it upstream
  2. Cap generated-input sizes in fuzzing harnesses
  3. 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

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


AI-assisted analysis of astral-sh/ruff@15f3fe6b15 (2026-08-20). Data as JSON: /api/errors/519a0f6a175a6aef. Report an issue: GitHub.