{"record":{"id":"ba8bac1854e05900","repo":"rust-lang/rust-analyzer","slug":"can-t-find-syntaxnodeptr-in-astidmap","errorCode":null,"errorMessage":"Can't find SyntaxNodePtr {:?} in AstIdMap:\n{:?}","messagePattern":"Can't find SyntaxNodePtr (.+?) in AstIdMap:\n(.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/span/src/ast_id.rs","lineNumber":825,"sourceCode":"    }\n\n    pub fn ast_id_for_ptr<N: AstIdNode>(&self, ptr: AstPtr<N>) -> FileAstId<N> {\n        let ptr = ptr.syntax_node_ptr();\n        FileAstId { raw: self.erased_ast_id(ptr), _marker: PhantomData }\n    }\n\n    /// Blocks may not be allocated (if they have no items), so they have a different API.\n    pub fn ast_id_for_ptr_for_block(\n        &self,\n        ptr: AstPtr<ast::BlockExpr>,\n    ) -> Option<FileAstId<ast::BlockExpr>> {\n        let ptr = ptr.syntax_node_ptr();\n        self.try_erased_ast_id(ptr).map(|raw| FileAstId { raw, _marker: PhantomData })\n    }\n\n    fn erased_ast_id(&self, ptr: SyntaxNodePtr) -> ErasedFileAstId {\n        self.try_erased_ast_id(ptr).unwrap_or_else(|| {\n            panic!(\n                \"Can't find SyntaxNodePtr {:?} in AstIdMap:\\n{:?}\",\n                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);","sourceCodeStart":807,"sourceCodeEnd":843,"githubUrl":"https://github.com/rust-lang/rust-analyzer/blob/e8f7e90aa3e7b26aa9a000200f606c1078da99ec/crates/span/src/ast_id.rs#L807-L843","documentation":"`AstIdMap::erased_ast_id` maps a SyntaxNodePtr back to the compact FileAstId previously assigned for that node. If the pointer is not present in the map, the invariant 'every node whose ast_id is requested was seen when the map was built' is broken, so it panics with the pointer and a dump of all mapped nodes. AstIdMaps are rebuilt whenever the file changes, so this usually indicates a stale map paired with nodes from a different version of the file.","triggerScenarios":"Calling `erased_ast_id` (directly or via `FileAstId::new`-style APIs or the `check_all_nodes` validation) with a SyntaxNodePtr that was never inserted — e.g. a node created for a newer/older parse than the AstIdMap in use, a synthetic/fixup node never added to the map, or a node from a different file.","commonSituations":"Salsa query staleness where an AstIdMap input changed but a dependent query kept old node pointers; macro-expansion or syntax-fixup paths producing nodes outside the original file map; test code (`check_all_nodes`) walking nodes of a mismatched parse.","solutions":["Ensure the AstIdMap and the syntax nodes come from the same parse/version of the file (same salsa revision)","Rebuild the AstIdMap for the current file instead of reusing a cached one","Verify nodes created by fixup/expansion are either added to the map or never queried for ast ids"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Ensure the map and node come from the same parse before mapping:\nif map.file_version() != parse.version() {\n    map = rebuild_ast_id_map(parse); // re-query the AstIdMap for the current revision\n}\nlet id = map.erased_ast_id(ptr);","typeGuard":null,"tryCatchPattern":"// Only during debugging/tests, not in production paths:\nlet id = std::panic::catch_unwind(AssertUnwindSafe(|| map.erased_ast_id(ptr.clone())))\n    .ok()?; // then re-resolve from a fresh map","preventionTips":["Always obtain SyntaxNodePtr and AstIdMap from the same salsa query/revision","Never reuse AstIdMaps across file edits","Prefer try_erased_ast_id and handle None where staleness is possible"],"tags":["rust","panic","stale-data","salsa","ast"],"backgroundTag":"stale-ast-id-map","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"}