{"record":{"id":"04063b53e3fb4cec","repo":"rust-lang/rust-analyzer","slug":"placeholders-should-either-be-name-or-name-con","errorCode":null,"errorMessage":"Placeholders should either be $name or ${{name:constraints}}","messagePattern":"Placeholders should either be \\$name or (.+?)\\}","errorType":"validation","errorClass":"SsrError","httpStatus":null,"severity":"error","filePath":"crates/ide-ssr/src/parsing.rs","lineNumber":297,"sourceCode":"                    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();\n    match constraint_type.as_str() {\n        \"kind\" => {\n            expect_token(tokens, \"(\")?;\n            let t = tokens.next().ok_or_else(|| {\n                SsrError::new(\"Unexpected end of constraint while looking for kind\")","sourceCodeStart":279,"sourceCodeEnd":315,"githubUrl":"https://github.com/rust-lang/rust-analyzer/blob/e8f7e90aa3e7b26aa9a000200f606c1078da99ec/crates/ide-ssr/src/parsing.rs#L279-L315","documentation":"SSR placeholders must match $name or ${name:constraints}; if the token after '$' is neither a valid identifier nor an opening '{', parse_placeholder bails with this message. The parse then fails and the whole pattern is rejected.","triggerScenarios":"Writing patterns like 'foo($' (dollar at end), '$ kind(literal)', or '$-x' where the character after '$' is not an identifier or '{'.","commonSituations":"Typing $ followed by a digit or punctuation in the IDE structural search box; scripting pattern generation that concatenates '$' with a non-identifier; confusing SSR placeholders with regex groups.","solutions":["Use a bare identifier after $: $name","Or use the braced form with constraints: ${name:kind(literal)}","Remove stray characters between '$' and the placeholder name"],"exampleFix":"// before\nlet pattern = \"foo($1)\";\n// after\nlet pattern = \"foo($arg)\";","handlingStrategy":"validation","validationCode":"fn has_wellformed_placeholders(p: &str) -> bool {\n    let bytes = p.as_bytes();\n    let mut i = 0;\n    while i < bytes.len() {\n        if bytes[i] == b'$' {\n            match bytes.get(i + 1) {\n                Some(&b) if b.is_ascii_alphabetic() || b == b'_' => {}\n                Some(&b'{') => {}\n                _ => return false, // $ not followed by ident or '{'\n            }\n        }\n        i += 1;\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(\"Placeholders should either be\") => {\n        eprintln!(\"Fix placeholder: must be $name or ${{name:constraints}}\");\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Never place digits or punctuation directly after $","Name placeholders with identifiers: $arg, not $1","Complete the ${...} form when opening a brace","Lint generated patterns for bare '$' characters"],"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"}