{"record":{"id":"519a0f6a175a6aef","repo":"astral-sh/ruff","slug":"expected-live-bindings-length-to-fit-into-a-u32","errorCode":null,"errorMessage":"Expected live-bindings length to fit into a u32","messagePattern":"Expected live-bindings length to fit into a u32","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/ty_python_core/src/use_def.rs","lineNumber":489,"sourceCode":"struct RetainedBindingsBuilder {\n    ends: IndexVec<InternedBindingsId, u32>,\n    live_bindings: Vec<LiveBinding>,\n}\n\nimpl RetainedBindingsBuilder {\n    fn with_capacity(bindings: usize) -> Self {\n        Self {\n            ends: IndexVec::with_capacity(bindings),\n            live_bindings: Vec::with_capacity(bindings),\n        }\n    }\n\n    fn push(&mut self, bindings: &Bindings) -> InternedBindingsId {\n        // Definition IDs are also 32-bit and a single scope cannot practically approach this\n        // limit. Keeping one cumulative end offset per state halves the retained range metadata.\n        self.live_bindings.extend_from_slice(bindings.as_slice());\n        let end = u32::try_from(self.live_bindings.len())\n            .expect(\"Expected live-bindings length to fit into a u32\");\n        self.ends.push(end)\n    }\n\n    fn get(&self, index: InternedBindingsId) -> &[LiveBinding] {\n        let end = self.ends[index];\n        let start = if index.index() == 0 {\n            0\n        } else {\n            self.ends[InternedBindingsId::new(index.index() - 1)]\n        };\n        &self.live_bindings[start as usize..end as usize]\n    }\n\n    fn finish(\n        self,\n        narrowing_constraints: &mut NarrowingConstraintsBuilder,\n        reachability_constraints: &mut ReachabilityConstraintsBuilder,\n    ) -> RetainedBindings {","sourceCodeStart":471,"sourceCodeEnd":507,"githubUrl":"https://github.com/astral-sh/ruff/blob/15f3fe6b15a5f00172f34b0f542f8ea277f5a586/crates/ty_python_core/src/use_def.rs#L471-L507","documentation":"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.","triggerScenarios":"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.","commonSituations":"Fuzzers or code generators emitting pathological binding counts; not observed with human-scale codebases.","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"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// fuzz harnesses: cap bindings per run far below u32::MAX\nif total_bindings > 100_000_000 { return; } // abandon pathological inputs","typeGuard":null,"tryCatchPattern":"let ok = std::panic::catch_unwind(|| intern_bindings(&scopes)); // isolate in long-running tools","preventionTips":["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"],"tags":["internal","invariant","panic","integer-overflow","data-structure"],"backgroundTag":"internal-invariant-violation","analyzedSha":"15f3fe6b15a5f00172f34b0f542f8ea277f5a586","analyzedAt":"2026-08-20T16:33:49.445Z","contentChangedAt":"2026-08-20T16:33:49.445Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}