rust-lang/rust-analyzer · error
invalid delimiter `{delimiter:?}`
Error message
invalid delimiter `{delimiter:?}` What it means
`make::token_tree(delimiter, tt)` builds an `ast::TokenTree` by rendering `tt!(...)` with the given delimiter. It only accepts the three group-opening punct kinds `T!['(']`, `T!['[']`, `T!['{']`; any other `SyntaxKind` hits the `_` arm and panics with `invalid delimiter`. The FileChange/fmt/set_roots mention in the error metadata refers to unrelated same-workspace symbols and is not the throwing item.
Source
Thrown at crates/syntax/src/ast/make.rs:1363
inner: impl IntoIterator<Item = ast::Meta>,
) -> ast::CfgAttrMeta {
let inner = inner.into_iter().join(", ");
ast_from_text(&format!("#![cfg_attr({predicate}, {inner})]"))
}
pub fn cfg_flag(flag: &str) -> ast::CfgPredicate {
ast_from_text(&format!("#![cfg({flag})]"))
}
pub fn token_tree(
delimiter: SyntaxKind,
tt: impl IntoIterator<Item = NodeOrToken<ast::TokenTree, SyntaxToken>>,
) -> ast::TokenTree {
let (l_delimiter, r_delimiter) = match delimiter {
T!['('] => ('(', ')'),
T!['['] => ('[', ']'),
T!['{'] => ('{', '}'),
_ => panic!("invalid delimiter `{delimiter:?}`"),
};
let tt = tt.into_iter().join("");
ast_from_text(&format!("tt!{l_delimiter}{tt}{r_delimiter}"))
}
pub fn expr_let(pattern: ast::Pat, expr: ast::Expr) -> ast::LetExpr {
expr_from_text(&format!("while let {pattern} = {expr} {{}}"))
}
#[track_caller]
fn expr_from_text<E: Into<ast::Expr> + AstNode>(text: &str) -> E {
expr_from_text_with_edition(text, Edition::CURRENT)
}
#[track_caller]
fn expr_from_text_with_edition<E: Into<ast::Expr> + AstNode>(text: &str, edition: Edition) -> E {
let parse = ast::Expr::parse(text, edition);View on GitHub (pinned to e8f7e90aa3)
Solutions
- Pass exactly one of `T!['(']`, `T!['[']`, `T!['{']` (punctuation SyntaxKinds, not `DelimiterKind` values).
- Map `tt::DelimiterKind` explicitly: Parenthesis→`T!['(']`, Brace→`T!['{']`, Bracket→`T!['[']`, and handle/skip `Invisible` before calling.
- Validate the kind with a match before calling and fall back to a default delimiter for unexpected values.
Example fix
// before
make::token_tree(T![')'], items); // panics: invalid delimiter
// after
make::token_tree(T!['('], items); Defensive patterns
Strategy: validation
Validate before calling
fn is_valid_delimiter(kind: syntax::SyntaxKind) -> bool {
use syntax::SyntaxKind::*;
matches!(kind, T!['('] | T!['['] | T!['{'])
}
// if !is_valid_delimiter(kind) { return Err(...) } Type guard
fn to_delimiters(kind: syntax::SyntaxKind) -> Option<(char, char)> {
use syntax::SyntaxKind as K;
match kind {
K::L_PAREN => Some(('(', ')')),
K::L_BRACK => Some(('[', ']')),
K::L_CURLY => Some(('{', '}')),
_ => None,
}
} Prevention
- Only pass `T!['(']`, `T!['[']`, or `T!['{']` to `make::token_tree`.
- Convert `tt::DelimiterKind` to punct SyntaxKinds via an exhaustive match and handle `Invisible` separately.
- Never pass closing-delimiter or non-punct SyntaxKinds.
When it happens
Trigger: Calling `make::token_tree` with a `SyntaxKind` other than `T!['(']`, `T!['[']`, `T!['{']` — e.g. a closing-kind like `T![')']`, an arbitrary token kind, or a kind derived from a `tt::DelimiterKind` without handling `Invisible`.
Common situations: Mapping a `tt::DelimiterKind`/token kind to a make-delimiter with an incomplete match; delimiters read from token streams where `Invisible` maps to no punct kind; passing a closing delimiter kind by mistake.
Related errors
- dynamic `SyntaxKind` for `AstNode::kind()`
- Can't find SyntaxNodePtr {:?} in AstIdMap: {:?}
- AstIdMap node mismatch with node `{ptr:?}`
- Can't find ast id {:?} in AstIdMap: {:?}
- Failed to make expr node `{node}` from text `{text}`
AI-assisted analysis of rust-lang/rust-analyzer@e8f7e90aa3 (2026-09-03).
Data as JSON: /api/errors/3ed1e3977e8ad97a.
Report an issue: GitHub.