rust-lang/rust-analyzer · error
Can't find SyntaxNodePtr {:?} in AstIdMap: {:?}
Error message
Can't find SyntaxNodePtr {:?} in AstIdMap:
{:?} What it means
`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.
Source
Thrown at crates/span/src/ast_id.rs:825
}
pub fn ast_id_for_ptr<N: AstIdNode>(&self, ptr: AstPtr<N>) -> FileAstId<N> {
let ptr = ptr.syntax_node_ptr();
FileAstId { raw: self.erased_ast_id(ptr), _marker: PhantomData }
}
/// Blocks may not be allocated (if they have no items), so they have a different API.
pub fn ast_id_for_ptr_for_block(
&self,
ptr: AstPtr<ast::BlockExpr>,
) -> Option<FileAstId<ast::BlockExpr>> {
let ptr = ptr.syntax_node_ptr();
self.try_erased_ast_id(ptr).map(|raw| FileAstId { raw, _marker: PhantomData })
}
fn erased_ast_id(&self, ptr: SyntaxNodePtr) -> ErasedFileAstId {
self.try_erased_ast_id(ptr).unwrap_or_else(|| {
panic!(
"Can't find SyntaxNodePtr {:?} in AstIdMap:\n{:?}",
ptr,
self.arena.iter().map(|(_id, i)| i).collect::<Vec<_>>(),
)
})
}
fn try_erased_ast_id(&self, ptr: SyntaxNodePtr) -> Option<ErasedFileAstId> {
let hash = hash_ptr(&ptr);
let idx = *self.ptr_map.find(hash, |&idx| self.arena[idx].0 == ptr)?;
Some(self.arena[idx].1)
}
// Don't bound on `AstIdNode` here, because `BlockExpr`s are also valid here (`ast::BlockExpr`
// doesn't always have a matching `FileAstId`, but a `FileAstId<ast::BlockExpr>` always has
// a matching node).
pub fn get<N: AstNode>(&self, id: FileAstId<N>) -> AstPtr<N> {
let ptr = self.get_erased(id.raw);View on GitHub (pinned to e8f7e90aa3)
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
Defensive patterns
Strategy: validation
Validate before calling
// Ensure the map and node come from the same parse before mapping:
if map.file_version() != parse.version() {
map = rebuild_ast_id_map(parse); // re-query the AstIdMap for the current revision
}
let id = map.erased_ast_id(ptr); Try / catch
// Only during debugging/tests, not in production paths:
let id = std::panic::catch_unwind(AssertUnwindSafe(|| map.erased_ast_id(ptr.clone())))
.ok()?; // then re-resolve from a fresh map Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Can't find ast id {:?} in AstIdMap: {:?}
- AstIdMap node mismatch with node `{ptr:?}`
- We explicitly do not provide canonicalization API, as that i
- bad kind {other}
- bad spacing {other}
AI-assisted analysis of rust-lang/rust-analyzer@e8f7e90aa3 (2026-09-03).
Data as JSON: /api/errors/ba8bac1854e05900.
Report an issue: GitHub.