rust-lang/rust-analyzer · error
Failed to parse pattern: {}
Error message
Failed to parse pattern: {} What it means
This error comes from the structural search/replace (SSR) pattern tokenizer. Before splitting the pattern into tokens, the pattern source is run through the rust-analyzer lexer; if the lexer reports any error (unbalanced quotes, bad characters, unterminated constructs), the whole pattern is rejected with this message carrying the underlying lexer error text. It fires early in parse_pattern via tokenize, so nothing is matched at all.
Source
Thrown at crates/ide-ssr/src/parsing.rs:260
if let PatternElement::Placeholder(placeholder) = p {
if !defined_placeholders.contains(&placeholder.ident) {
undefined.push(placeholder.ident.to_string());
}
if !placeholder.constraints.is_empty() {
bail!("Replacement placeholders cannot have constraints");
}
}
}
if !undefined.is_empty() {
bail!("Replacement contains undefined placeholders: {}", undefined.join(", "));
}
Ok(())
}
fn tokenize(source: &str) -> Result<Vec<Token>, SsrError> {
let lexed = parser::LexedStr::new(parser::Edition::CURRENT, source);
if let Some((_, first_error)) = lexed.errors().next() {
bail!("Failed to parse pattern: {}", first_error);
}
let mut tokens: Vec<Token> = Vec::new();
for i in 0..lexed.len() {
tokens.push(Token { kind: lexed.kind(i), text: lexed.text(i).into() });
}
Ok(tokens)
}
fn parse_placeholder(tokens: &mut std::vec::IntoIter<Token>) -> Result<Placeholder, SsrError> {
let mut name = None;
let mut constraints = Vec::new();
if let Some(token) = tokens.next() {
match token.kind {
SyntaxKind::IDENT => {
name = Some(token.text);
}
T!['{'] => {
let token =View on GitHub (pinned to e8f7e90aa3)
Solutions
- Read the embedded first_error text and fix the lexical problem (unterminated string/comment, illegal character) in the pattern
- Verify the pattern is a complete, lexable Rust fragment before passing it to the SSR API
- Escape special characters (quotes, braces) that were introduced by shell/string interpolation
Example fix
// before let pattern = "fn foo( -> u32"; // unterminated paren/lexer garbage // after let pattern = "fn foo() -> u32";
Defensive patterns
Strategy: validation
Validate before calling
fn is_lexable(pattern: &str) -> bool {
let lexed = ide_ssr::parsing_lexer(pattern);
lexed.errors().next().is_none()
}
// reject patterns where is_lexable returns false before calling the SSR API Type guard
fn is_valid_ssr_pattern(p: &str) -> bool {
!p.trim().is_empty() && p.chars().all(|c| !matches!(c, '\u{0}'))
}
Try / catch
match SearchPattern::new(&pattern) {
Ok(p) => apply(p),
Err(e) if e.message.starts_with("Failed to parse pattern") => {
eprintln!("Invalid SSR pattern (lexer): {}", e.message);
}
Err(e) => return Err(e),
} Prevention
- Test patterns in the IDE structural search box before scripting them
- Check quotes and comments are balanced in the pattern
- Escape quotes when embedding patterns in strings or shells
- Keep patterns as complete Rust fragments
When it happens
Trigger: Calling any ide-ssr API that parses a search or replace pattern (e.g. parse_pattern via SearchPattern::new) with source containing a lexing error, such as an unterminated string literal or invalid character, as detected by parser::LexedStr::new errors().
Common situations: Typing an SSR search pattern in the IDE's structural search box with a stray or unbalanced quote; programmatically building patterns with string interpolation that leaves broken syntax; copying a code snippet that includes an incomplete fragment.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Unexpected token while parsing placeholder: '{}'
- Placeholders should either be $name or ${{name:constraints}}
- Expected ident, found {:?} while parsing kind constraint
- Unsupported constraint type '{}'
- Expected {} found {}
AI-assisted analysis of rust-lang/rust-analyzer@e8f7e90aa3 (2026-09-03).
Data as JSON: /api/errors/3a573ceff5050aaa.
Report an issue: GitHub.