rust-lang/rust-analyzer · error
No files to search
Error message
No files to search
What it means
ide-ssr's `at_first_file` entry point requires at least one file to operate on: it picks the first file, creates a MatchFinder rooted at that file position, and only then applies SSR rules. When the supplied file list (or the resolution of the requested file) yields no file id, the library cannot anchor the search anywhere, so it fails fast with `bail!("No files to search")`.
Source
Thrown at crates/ide-ssr/src/lib.rs:156
.ok_or_else(|| SsrError("no resolution scope for file".into()))?;
Ok(MatchFinder { sema, rules: Vec::new(), resolution_scope, restrict_ranges })
}
/// Constructs an instance using the start of the first file in `db` as the lookup context.
pub fn at_first_file(db: &'db ide_db::RootDatabase) -> Result<MatchFinder<'db>, SsrError> {
if let Some(first_file_id) = LocalRoots::get(db)
.roots(db)
.iter()
.next()
.and_then(|root| db.source_root(*root).source_root(db).iter().next())
{
MatchFinder::in_context(
db,
ide_db::FilePosition { file_id: first_file_id, offset: 0.into() },
vec![],
)
} else {
bail!("No files to search");
}
}
/// Adds a rule to be applied. The order in which rules are added matters. Earlier rules take
/// precedence. If a node is matched by an earlier rule, then later rules won't be permitted to
/// match to it.
pub fn add_rule(&mut self, rule: SsrRule) -> Result<(), SsrError> {
for parsed_rule in rule.parsed_rules {
self.rules.push(ResolvedRule::new(
parsed_rule,
&self.resolution_scope,
self.rules.len(),
)?);
}
Ok(())
}
/// Finds matches for all added rules and returns edits for all found matches.View on GitHub (pinned to e8f7e90aa3)
Solutions
- Ensure at least one file is resolved to a valid `FileId` before calling the SSR entry point.
- Check the file collection for emptiness and bail early in your own code with a clearer message (e.g. 'open a file first').
- If files should exist, verify the VFS/load path: the file may not be added to the database yet.
- Fall back to the multi-file API (`MatchFinder::in_context` with your own file list) only after confirming it is non-empty.
Example fix
// before let ssr = SsrPattern::at_first_file(db, /* files possibly empty */)?; // after anyhow::ensure!(!file_ids.is_empty(), "SSR requires at least one open file"); let ssr = SsrPattern::at_first_file(db, file_ids)?;
Defensive patterns
Strategy: validation
Validate before calling
// caller-side pre-check before invoking SSR
if file_ids.is_empty() {
return Err(anyhow::anyhow!("SSR needs at least one resolved file; got none"));
}
let ssr = SsrPattern::at_first_file(db, file_ids)?; Type guard
fn has_files(files: &[FileId]) -> bool { !files.is_empty() } Try / catch
match SsrPattern::at_first_file(db, file_ids) {
Ok(s) => s,
Err(e) if e.to_string().contains("No files to search") => {
eprintln!("No files loaded for SSR; open/resolve a file first");
return Ok(());
}
Err(e) => return Err(e.into()),
} Prevention
- Resolve file paths to FileIds and assert the list is non-empty before SSR
- Confirm the VFS/workspace has finished loading before running batch search/replace
- Handle 'nothing loaded' states in the UI/CLI instead of passing empty collections downstream
When it happens
Trigger: Calling `SsrPattern/MatchFinder::at_first_file` (or the ide-ssr API backed by it, e.g. structural search/replace via `ide_db` handlers) with an empty file-id vector, or with input whose file resolution produced no valid `FileId` (e.g. an unopened/nonexistent file filtered out upstream).
Common situations: Batch refactoring scripts driven over a VFS snapshot where no files were loaded yet; editors invoking SSR before the workspace finished loading; callers passing a path that failed to resolve to a FileId so the resulting collection is empty.
Related errors
- Not a valid Rust expression, type, item, path or pattern
- Placeholder `{}` repeats more than once
- Replacement placeholders cannot have constraints
- Replacement contains undefined placeholders: {}
- We explicitly do not provide canonicalization API, as that i
AI-assisted analysis of rust-lang/rust-analyzer@e8f7e90aa3 (2026-09-03).
Data as JSON: /api/errors/5e6b63966a201ae2.
Report an issue: GitHub.