{"record":{"id":"984b7106a5920c32","repo":"rust-lang/rust-analyzer","slug":"not-a-valid-rust-expression-type-item-path-or-p","errorCode":null,"errorMessage":"Not a valid Rust expression, type, item, path or pattern","messagePattern":"Not a valid Rust expression, type, item, path or pattern","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/ide-ssr/src/parsing.rs","lineNumber":118,"sourceCode":"    ) {\n        match (pattern, template) {\n            (Ok(pattern), Some(Ok(template))) => self.rules.push(ParsedRule {\n                placeholders_by_stand_in: self.placeholders_by_stand_in.clone(),\n                pattern,\n                template: Some(template),\n            }),\n            (Ok(pattern), None) => self.rules.push(ParsedRule {\n                placeholders_by_stand_in: self.placeholders_by_stand_in.clone(),\n                pattern,\n                template: None,\n            }),\n            _ => {}\n        }\n    }\n\n    fn build(mut self) -> Result<Vec<ParsedRule>, SsrError> {\n        if self.rules.is_empty() {\n            bail!(\"Not a valid Rust expression, type, item, path or pattern\");\n        }\n        // If any rules contain paths, then we reject any rules that don't contain paths. Allowing a\n        // mix leads to strange semantics, since the path-based rules only match things where the\n        // path refers to semantically the same thing, whereas the non-path-based rules could match\n        // anything. Specifically, if we have a rule like `foo ==>> bar` we only want to match the\n        // `foo` that is in the current scope, not any `foo`. However \"foo\" can be parsed as a\n        // pattern (IDENT_PAT -> NAME -> IDENT). Allowing such a rule through would result in\n        // renaming everything called `foo` to `bar`. It'd also be slow, since without a path, we'd\n        // have to use the slow-scan search mechanism.\n        if self.rules.iter().any(|rule| contains_path(&rule.pattern)) {\n            let old_len = self.rules.len();\n            self.rules.retain(|rule| contains_path(&rule.pattern));\n            if self.rules.len() < old_len {\n                cov_mark::hit!(pattern_is_a_single_segment_path);\n            }\n        }\n        Ok(self.rules)\n    }","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/rust-lang/rust-analyzer/blob/e8f7e90aa3e7b26aa9a000200f606c1078da99ec/crates/ide-ssr/src/parsing.rs#L100-L136","documentation":"`ParsedRule::new` delegates to `build`, which parses the user's search/replacement pattern into `ParsedRule`s. If nothing could be parsed into a rule — the token stream produced no rules — the library rejects the pattern string because it is not a Rust expression, type, item, path, or pattern, i.e. it is syntactically meaningless to SSR.","triggerScenarios":"Calling `SsrPattern::new`/`from_str` with a pattern string that parses to zero rules — e.g. an empty string, only whitespace/comments, or text that the parser cannot interpret as any of expression/type/item/path/pattern (garbage tokens, unbalanced delimiters consumed as trivia).","commonSituations":"Typo or truncation when passing an SSR rule from a CLI flag or editor config; shell quoting stripping the pattern (e.g. `$var` expanded away); passing a full `foo ==>> bar` rule string where only a pattern is expected, or vice versa, causing parse failure.","solutions":["Verify the pattern string is non-empty and contains real Rust syntax (e.g. `foo()`, `Some($x)`, `foo($a) ==>> bar($a)`).","Print/log the exact string reaching SSR — shell quoting or config interpolation may have mangled it.","Feed a minimal known-good pattern to confirm the API wiring, then build up your real pattern incrementally.","Check for unbalanced parentheses/brackets that cause the whole parse to be discarded."],"exampleFix":"// before\nlet rule = SsrPattern::new(\"$\"); // garbage -> no rules parsed\n// after\nlet rule = SsrPattern::new(\"foo($arg) ==>> bar($arg)\").unwrap();","handlingStrategy":"validation","validationCode":"fn looks_like_pattern(s: &str) -> bool {\n    let t = s.trim();\n    !t.is_empty() && t.chars().any(|c| !c.is_whitespace()) && t.contains(|c: char| c.is_alphanumeric() || c == '_')\n}\n// then: anyhow::ensure!(looks_like_pattern(&pat), \"invalid SSR pattern: {:?}\", pat);","typeGuard":"fn is_valid_rule_input(s: &str) -> bool {\n    matches!(s.trim(), t if !t.is_empty() && rust_lexer_yields_tokens(t))\n}","tryCatchPattern":"match SsrPattern::new(&pat) {\n    Ok(p) => p,\n    Err(e) if e.to_string().contains(\"Not a valid Rust\") => {\n        eprintln!(\"Pattern {:?} is not valid Rust syntax; check quoting/escaping\", pat);\n        return Ok(());\n    }\n    Err(e) => return Err(e.into()),\n}","preventionTips":["Validate the rule string is non-empty after config/shell expansion","Beware shell quoting: single-quote SSR patterns so `$placeholders` survive","Test patterns incrementally starting from a known-good minimal rule","Check for unbalanced delimiters before feeding complex patterns to SSR"],"tags":["rust","ide-ssr","parse-error","invalid-pattern"],"backgroundTag":"pattern-parse-failed","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"}