rust-lang/rust-analyzer · error · SsrError
Unexpected token while parsing placeholder: '{}'
Error message
Unexpected token while parsing placeholder: '{}' What it means
When parsing an SSR placeholder, the parser accepts either $name or ${name:constraints}. Inside the ${...} form, only ':' (starting a constraint) or '}' (ending the placeholder) may follow the name; any other token triggers this error naming the offending token text. It is raised inside parse_placeholder, invoked from parse_pattern.
Source
Thrown at crates/ide-ssr/src/parsing.rs:292
SyntaxKind::IDENT => {
name = Some(token.text);
}
T!['{'] => {
let token =
tokens.next().ok_or_else(|| SsrError::new("Unexpected end of placeholder"))?;
if token.kind == SyntaxKind::IDENT {
name = Some(token.text);
}
loop {
let token = tokens
.next()
.ok_or_else(|| SsrError::new("Placeholder is missing closing brace '}'"))?;
match token.kind {
T![:] => {
constraints.push(parse_constraint(tokens)?);
}
T!['}'] => break,
_ => bail!("Unexpected token while parsing placeholder: '{}'", token.text),
}
}
}
_ => {
bail!("Placeholders should either be $name or ${{name:constraints}}");
}
}
}
let name = name.ok_or_else(|| SsrError::new("Placeholder ($) with no name"))?;
Ok(Placeholder::new(name, constraints))
}
fn parse_constraint(tokens: &mut std::vec::IntoIter<Token>) -> Result<Constraint, SsrError> {
let constraint_type = tokens
.next()
.ok_or_else(|| SsrError::new("Found end of placeholder while looking for a constraint"))?
.text
.to_string();View on GitHub (pinned to e8f7e90aa3)
Solutions
- Use ':' before constraints: ${name:kind(literal)}
- Close the placeholder with '}' if no constraints are needed: ${name} — or just use $name
- Check the token text in the message and remove/replace the unexpected character
Example fix
// before
let pattern = "foo(${x = kind(literal)})";
// after
let pattern = "foo(${x:kind(literal)})"; Defensive patterns
Strategy: validation
Validate before calling
fn valid_placeholder_syntax(p: &str) -> bool {
let mut chars = p.char_indices();
while let Some((i, c)) = chars.next() {
if c == '$' {
match chars.next() {
Some((_, n)) if n.is_alphabetic() || n == '_' => {}
Some((_, '{')) => {
let rest = &p[i + 2..];
if let Some(end) = rest.find('}') {
let inner = &rest[..end];
if !inner.contains('=') && !inner.contains(' ') { continue; }
return false; // only ':' constraints allowed inside
}
return false; // unterminated ${
}
_ => return false,
}
}
}
true
}
Try / catch
match parse_pattern(pattern) {
Ok(p) => use_pattern(p),
Err(e) if e.message.contains("Unexpected token while parsing placeholder") => {
eprintln!("Bad placeholder: use $name or ${{name:constraints}}");
}
Err(e) => return Err(e),
} Prevention
- Use $name unless you need constraints
- Inside ${...}, separate constraints only with ':' and close with '}'
- Do not reuse shell/mustache ${var} syntax inside SSR patterns
- Preview patterns in the IDE search box first
When it happens
Trigger: Writing an SSR pattern with ${name followed by a token that is neither ':' nor '}', e.g. '${name kind}' or '${name=Constraint}', or inserting whitespace-adjacent invalid syntax inside the braces.
Common situations: Hand-writing constraint syntax from memory and getting the separator wrong; mixing shell/mustache ${var} habits with SSR's constrained grammar; IDE search box typos.
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
- Placeholders should either be $name or ${{name:constraints}}
- Failed to parse pattern: {}
- 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/40c8e18070121aa8.
Report an issue: GitHub.