{"record":{"id":"d6bc26410d8ea977","repo":"astral-sh/ruff","slug":"extra-use-def-data-should-have-been-retained","errorCode":null,"errorMessage":"extra use-def data should have been retained","messagePattern":"extra use-def data should have been retained","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/ty_python_core/src/use_def.rs","lineNumber":870,"sourceCode":"    }\n}\n\npub enum ApplicableConstraints<'map, 'db> {\n    UnboundBinding(NarrowingEvaluator<'map, 'db>),\n    ConstrainedBindings(BindingWithConstraintsIterator<'map, 'db>),\n}\n\nimpl<'db> UseDefMap<'db> {\n    fn constraint_tables(&self) -> &ConstraintTables<'db> {\n        self.constraint_tables\n            .as_deref()\n            .map_or(&EMPTY_CONSTRAINT_TABLES, |tables| tables)\n    }\n\n    fn extra(&self) -> &UseDefMapExtra {\n        self.extra\n            .as_deref()\n            .expect(\"extra use-def data should have been retained\")\n    }\n\n    pub fn loop_header(&self, id: LoopHeaderId) -> &LoopHeader {\n        &self.extra().loop_headers[id]\n    }\n\n    pub fn reachability_constraints(&self) -> &ReachabilityConstraints {\n        &self.constraint_tables().reachability_constraints\n    }\n\n    pub fn predicates(&self) -> &Predicates<'db> {\n        &self.constraint_tables().predicates\n    }\n\n    pub fn range_reachability(\n        &self,\n    ) -> impl Iterator<Item = (TextRange, ScopedReachabilityConstraintId)> + '_ {\n        self.range_reachability","sourceCodeStart":852,"sourceCodeEnd":888,"githubUrl":"https://github.com/astral-sh/ruff/blob/d1087a4b9e03d253a88703f34e0869ee4b805456/crates/ty_python_core/src/use_def.rs#L852-L888","documentation":"UseDefMap stores rarely used tables (bindings-by-use, member place states, enclosing snapshots, loop headers) in an optional extra box that is only allocated when at least one of those collections is non-empty when the map finishes building (use_def.rs:2925-2937). extra() panics when an accessor that reads those tables (loop_header, member end-of-scope queries, bindings-by-use lookups) is called on a map built with extra == None.","triggerScenarios":"Calling UseDefMap::loop_header(LoopHeaderId), end_of_scope_declarations on a member place, or a bindings-by-use lookup on a map whose four extra collections were all empty at finish time. In practice this means the ID being looked up came from a different or stale use-def map revision, or a builder path recorded IDs but dropped their table.","commonSituations":"Editor/LSP flows where a cached LoopHeaderId or ScopedPlaceId outlives the Salsa revision that produced it after an edit; new query code that assumes a table always exists without checking that the module contains loops, member places, or multi-bindings.","solutions":["Re-derive LoopHeaderId/ScopedPlaceId/use IDs from the current semantic model instead of caching them across revisions, so IDs and the map they index come from the same snapshot","Guard the query: only call extra-backed accessors for constructs that exist in this file's current semantic index (e.g., only for loops actually present)","If the ID provably came from the same map, capture the backtrace and file a ty issue: the map handed out an ID whose backing table it did not retain"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Re-derive IDs from the current snapshot instead of caching them:\nlet index = semantic_index(db, file); // current revision\nlet loop_id = index.loop_header(loop_node); // matches this UseDefMap\nlet header = use_def_map.loop_header(loop_id);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never cache LoopHeaderId, ScopedPlaceId, or use IDs across Salsa revisions or edits; re-derive them per query","Only call extra-backed accessors (loop_header, member end-of-scope queries) for constructs present in the current file's semantic index","When adding new UseDefMap queries, assert the corresponding table exists for the file shape before reading it"],"tags":["rust","ty","use-def","panic","stale-state","internal-invariant"],"backgroundTag":"missing-optional-data-access","analyzedSha":"d1087a4b9e03d253a88703f34e0869ee4b805456","analyzedAt":"2026-08-20T16:33:49.445Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}