rust-lang/rust-analyzer · error
this node should have an ast id
Error message
this node should have an ast id
What it means
While building the AstIdMap, every remaining node in the traversal is expected to have an AST id computable via ErasedFileAstId::ast_id_for. If a node cannot be assigned an id the expect panics with 'this node should have an ast id'. It guards the invariant that the map is total over the file's syntax tree.
Source
Thrown at crates/span/src/ast_id.rs:721
}) && anc.next().is_some_and(|it| {
it.kind() == SyntaxKind::EXPR_STMT
|| it.kind() == SyntaxKind::STMT_LIST
})
}))
{
let parent = parent_of(parent_idx, &res);
let block_ast_id =
block_expr_ast_id(last_block_node, &mut index_map, parent)
.expect("not a BlockExpr");
res.arena
.alloc((SyntaxNodePtr::new(last_block_node), block_ast_id));
*already_allocated = ContainsItems::Yes;
}
let parent = parent_of(parent_idx, &res);
let ast_id =
ErasedFileAstId::ast_id_for(&node, &mut index_map, parent)
.expect("this node should have an ast id");
let idx = res.arena.alloc((SyntaxNodePtr::new(&node), ast_id));
next_layer.extend(node.children().map(|child| (child, Some(idx))));
preorder.skip_subtree();
}
}
syntax::WalkEvent::Leave(node) => {
if ast::BlockExpr::can_cast(node.kind()) {
let block = blocks.pop();
debug_assert_eq!(
block.map(|it| it.0),
Some(node),
"left a BlockExpr we never entered"
);
}
}
}
}View on GitHub (pinned to e8f7e90aa3)
Solutions
- Update all rust-analyzer crates together (parser, syntax, span, hir) so node-kind enums match.
- If you added a new syntax node kind, extend ErasedFileAstId::ast_id_for to handle it.
- Reduce the failing input to a minimal example and file an upstream issue.
- Verify no version skew: cargo update / consistent lockfile across the workspace.
Example fix
// before (new node kind missing from ast_id_for)
match node.kind() { ... } // no arm for the new kind
// after
match node.kind() {
SyntaxKind::MY_NEW_NODE => ...map it...,
...
} Defensive patterns
Strategy: fallback
Try / catch
match ErasedFileAstId::ast_id_for(&node, &mut index_map, parent) {
Some(id) => ..., // proceed
None => { /* skip node or report diagnostic instead of panicking */ }
} Prevention
- Extend ast_id_for whenever adding a new syntax node kind
- Keep the parser and span crates in the same lockfile revision
- File upstream reproductions when unknown node kinds appear from macros
When it happens
Trigger: from_source encounters a syntax node kind that ast_id_for cannot map — typically after parser changes, new/unknown node kinds from macro expansion, or a hand-constructed tree missing expected structure while processing top-level/item nodes in the arena traversal.
Common situations: rust-analyzer development: adding a new AST node kind without extending ast_id_for; synching the syntax crate versions across crates (span vs parser mismatch); fuzzed inputs producing novel tree shapes.
Related errors
- not a BlockExpr
- Can't find SyntaxNodePtr {:?} in AstIdMap: {:?}
- AstIdMap node mismatch with node `{ptr:?}`
- Can't find ast id {:?} in AstIdMap: {:?}
- dynamic `SyntaxKind` for `AstNode::kind()`
AI-assisted analysis of rust-lang/rust-analyzer@e8f7e90aa3 (2026-09-03).
Data as JSON: /api/errors/5641e9b9af5f34e8.
Report an issue: GitHub.