{"record":{"id":"40c8e18070121aa8","repo":"rust-lang/rust-analyzer","slug":"unexpected-token-while-parsing-placeholder","errorCode":null,"errorMessage":"Unexpected token while parsing placeholder: '{}'","messagePattern":"Unexpected token while parsing placeholder: '(.+?)'","errorType":"validation","errorClass":"SsrError","httpStatus":null,"severity":"error","filePath":"crates/ide-ssr/src/parsing.rs","lineNumber":292,"sourceCode":"            SyntaxKind::IDENT => {\n                name = Some(token.text);\n            }\n            T!['{'] => {\n                let token =\n                    tokens.next().ok_or_else(|| SsrError::new(\"Unexpected end of placeholder\"))?;\n                if token.kind == SyntaxKind::IDENT {\n                    name = Some(token.text);\n                }\n                loop {\n                    let token = tokens\n                        .next()\n                        .ok_or_else(|| SsrError::new(\"Placeholder is missing closing brace '}'\"))?;\n                    match token.kind {\n                        T![:] => {\n                            constraints.push(parse_constraint(tokens)?);\n                        }\n                        T!['}'] => break,\n                        _ => bail!(\"Unexpected token while parsing placeholder: '{}'\", token.text),\n                    }\n                }\n            }\n            _ => {\n                bail!(\"Placeholders should either be $name or ${{name:constraints}}\");\n            }\n        }\n    }\n    let name = name.ok_or_else(|| SsrError::new(\"Placeholder ($) with no name\"))?;\n    Ok(Placeholder::new(name, constraints))\n}\n\nfn parse_constraint(tokens: &mut std::vec::IntoIter<Token>) -> Result<Constraint, SsrError> {\n    let constraint_type = tokens\n        .next()\n        .ok_or_else(|| SsrError::new(\"Found end of placeholder while looking for a constraint\"))?\n        .text\n        .to_string();","sourceCodeStart":274,"sourceCodeEnd":310,"githubUrl":"https://github.com/rust-lang/rust-analyzer/blob/e8f7e90aa3e7b26aa9a000200f606c1078da99ec/crates/ide-ssr/src/parsing.rs#L274-L310","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nlet pattern = \"foo(${x = kind(literal)})\";\n// after\nlet pattern = \"foo(${x:kind(literal)})\";","handlingStrategy":"validation","validationCode":"fn valid_placeholder_syntax(p: &str) -> bool {\n    let mut chars = p.char_indices();\n    while let Some((i, c)) = chars.next() {\n        if c == '$' {\n            match chars.next() {\n                Some((_, n)) if n.is_alphabetic() || n == '_' => {}\n                Some((_, '{')) => {\n                    let rest = &p[i + 2..];\n                    if let Some(end) = rest.find('}') {\n                        let inner = &rest[..end];\n                        if !inner.contains('=') && !inner.contains(' ') { continue; }\n                        return false; // only ':' constraints allowed inside\n                    }\n                    return false; // unterminated ${\n                }\n                _ => return false,\n            }\n        }\n    }\n    true\n}\n","typeGuard":null,"tryCatchPattern":"match parse_pattern(pattern) {\n    Ok(p) => use_pattern(p),\n    Err(e) if e.message.contains(\"Unexpected token while parsing placeholder\") => {\n        eprintln!(\"Bad placeholder: use $name or ${{name:constraints}}\");\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["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"],"tags":["rust","parsing","ssr","placeholder-syntax"],"backgroundTag":"ssr-pattern-parse-error","analyzedSha":"e8f7e90aa3e7b26aa9a000200f606c1078da99ec","analyzedAt":"2026-09-03T21:08:06.959Z","contentChangedAt":"2026-09-03T21:08:06.959Z","schemaVersion":2},"datasetVersion":"2026-09-11T07:07:21.782Z"}