{"record":{"id":"1a17e575975c09a3","repo":"rust-lang/rust-analyzer","slug":"astidmap-node-mismatch-with-node-ptr","errorCode":null,"errorMessage":"AstIdMap node mismatch with node `{ptr:?}`","messagePattern":"AstIdMap node mismatch with node `(.+?)`","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/span/src/ast_id.rs","lineNumber":845,"sourceCode":"                ptr,\n                self.arena.iter().map(|(_id, i)| i).collect::<Vec<_>>(),\n            )\n        })\n    }\n\n    fn try_erased_ast_id(&self, ptr: SyntaxNodePtr) -> Option<ErasedFileAstId> {\n        let hash = hash_ptr(&ptr);\n        let idx = *self.ptr_map.find(hash, |&idx| self.arena[idx].0 == ptr)?;\n        Some(self.arena[idx].1)\n    }\n\n    // Don't bound on `AstIdNode` here, because `BlockExpr`s are also valid here (`ast::BlockExpr`\n    // doesn't always have a matching `FileAstId`, but a `FileAstId<ast::BlockExpr>` always has\n    // a matching node).\n    pub fn get<N: AstNode>(&self, id: FileAstId<N>) -> AstPtr<N> {\n        let ptr = self.get_erased(id.raw);\n        AstPtr::try_from_raw(ptr)\n            .unwrap_or_else(|| panic!(\"AstIdMap node mismatch with node `{ptr:?}`\"))\n    }\n\n    pub fn get_erased(&self, id: ErasedFileAstId) -> SyntaxNodePtr {\n        let hash = hash_ast_id(&id);\n        match self.id_map.find(hash, |&idx| self.arena[idx].1 == id) {\n            Some(&idx) => self.arena[idx].0,\n            None => panic!(\n                \"Can't find ast id {:?} in AstIdMap:\\n{:?}\",\n                id,\n                self.arena.iter().map(|(_id, i)| i).collect::<Vec<_>>(),\n            ),\n        }\n    }\n}\n\n#[cfg(not(no_salsa_async_drops))]\nimpl Drop for AstIdMap {\n    fn drop(&mut self) {","sourceCodeStart":827,"sourceCodeEnd":863,"githubUrl":"https://github.com/rust-lang/rust-analyzer/blob/e8f7e90aa3e7b26aa9a000200f606c1078da99ec/crates/span/src/ast_id.rs#L827-L863","documentation":"`AstIdMap::get` converts a stored FileAstId back into a typed AstPtr by first resolving the raw id to a SyntaxNodePtr and then re-typing it via `AstPtr::try_from_raw`. If the resolved pointer cannot be represented as the requested node type `N`, the encoded id/kind do not agree with the stored node — an internal encoding invariant violation — so it panics. This indicates the packed hash/index/kind encoding pointed at an entry whose kind does not match the requested type.","triggerScenarios":"Calling `map.get::<N>(id)` with a FileAstId<N> whose stored kind bits don't match N's kind — typically caused by a bug in pack_hash_index_and_kind/unpacking, an id from a different AstIdMap being looked up in the wrong map, or hash collisions corrupting the id_map lookup.","commonSituations":"Developers changing the ErasedFileAstId bit layout or hashing; cross-file/cross-version id reuse in salsa-cached queries; fuzzing inputs that expose kind-mismatch corruption.","solutions":["Verify the FileAstId was produced by the same AstIdMap instance you are querying","Check pack/unpack of hash, index, and kind bits after changing the encoding","Add/refresh the `check_all_nodes` consistency test to catch mismatches early"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Before get::<N>, confirm the kind matches the requested type:\nfn kind_matches<N: AstNode>(map: &AstIdMap, id: FileAstId<N>) -> bool {\n    map.raw_kind(id.raw) == N::kind()\n}","typeGuard":null,"tryCatchPattern":"let ptr = std::panic::catch_unwind(AssertUnwindSafe(|| map.get::<ast::Item>(id))).ok()?;","preventionTips":["Never decode or hand-construct ErasedFileAstId raw values","After changing the bit packing, run the AstIdMap consistency tests (check_all_nodes)","Keep ids scoped to the AstIdMap instance that produced them"],"tags":["rust","panic","invariant","ast","type-mismatch"],"backgroundTag":"ast-id-kind-mismatch","analyzedSha":"e8f7e90aa3e7b26aa9a000200f606c1078da99ec","analyzedAt":"2026-09-03T21:08:06.959Z","contentChangedAt":"2026-09-03T21:08:06.959Z","schemaVersion":2},"datasetVersion":"2026-09-11T07:07:21.782Z"}