rust-lang/rust-analyzer · error
Not a valid Rust expression, type, item, path or pattern
Error message
Not a valid Rust expression, type, item, path or pattern
What it means
`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.
Source
Thrown at crates/ide-ssr/src/parsing.rs:118
) {
match (pattern, template) {
(Ok(pattern), Some(Ok(template))) => self.rules.push(ParsedRule {
placeholders_by_stand_in: self.placeholders_by_stand_in.clone(),
pattern,
template: Some(template),
}),
(Ok(pattern), None) => self.rules.push(ParsedRule {
placeholders_by_stand_in: self.placeholders_by_stand_in.clone(),
pattern,
template: None,
}),
_ => {}
}
}
fn build(mut self) -> Result<Vec<ParsedRule>, SsrError> {
if self.rules.is_empty() {
bail!("Not a valid Rust expression, type, item, path or pattern");
}
// If any rules contain paths, then we reject any rules that don't contain paths. Allowing a
// mix leads to strange semantics, since the path-based rules only match things where the
// path refers to semantically the same thing, whereas the non-path-based rules could match
// anything. Specifically, if we have a rule like `foo ==>> bar` we only want to match the
// `foo` that is in the current scope, not any `foo`. However "foo" can be parsed as a
// pattern (IDENT_PAT -> NAME -> IDENT). Allowing such a rule through would result in
// renaming everything called `foo` to `bar`. It'd also be slow, since without a path, we'd
// have to use the slow-scan search mechanism.
if self.rules.iter().any(|rule| contains_path(&rule.pattern)) {
let old_len = self.rules.len();
self.rules.retain(|rule| contains_path(&rule.pattern));
if self.rules.len() < old_len {
cov_mark::hit!(pattern_is_a_single_segment_path);
}
}
Ok(self.rules)
}View on GitHub (pinned to e8f7e90aa3)
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.
Example fix
// before
let rule = SsrPattern::new("$"); // garbage -> no rules parsed
// after
let rule = SsrPattern::new("foo($arg) ==>> bar($arg)").unwrap(); Defensive patterns
Strategy: validation
Validate before calling
fn looks_like_pattern(s: &str) -> bool {
let t = s.trim();
!t.is_empty() && t.chars().any(|c| !c.is_whitespace()) && t.contains(|c: char| c.is_alphanumeric() || c == '_')
}
// then: anyhow::ensure!(looks_like_pattern(&pat), "invalid SSR pattern: {:?}", pat); Type guard
fn is_valid_rule_input(s: &str) -> bool {
matches!(s.trim(), t if !t.is_empty() && rust_lexer_yields_tokens(t))
} Try / catch
match SsrPattern::new(&pat) {
Ok(p) => p,
Err(e) if e.to_string().contains("Not a valid Rust") => {
eprintln!("Pattern {:?} is not valid Rust syntax; check quoting/escaping", pat);
return Ok(());
}
Err(e) => return Err(e.into()),
} Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- No files to search
- Placeholder `{}` repeats more than once
- Replacement placeholders cannot have constraints
- Replacement contains undefined placeholders: {}
- macro definition has parse errors
AI-assisted analysis of rust-lang/rust-analyzer@e8f7e90aa3 (2026-09-03).
Data as JSON: /api/errors/984b7106a5920c32.
Report an issue: GitHub.