{"record":{"id":"f719c6ee4b2b0a03","repo":"astral-sh/ruff","slug":"expected-at-least-one-path-to-search-for-python-fi","errorCode":null,"errorMessage":"Expected at least one path to search for Python files","messagePattern":"Expected at least one path to search for Python files","errorType":"console","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/ruff_workspace/src/resolver.rs","lineNumber":478,"sourceCode":"                } else {\n                    // We already visited this ancestor, we can stop here.\n                    break;\n                }\n            }\n        }\n    }\n\n    // Check if the paths themselves are excluded.\n    if resolver.force_exclude() {\n        paths.retain(|path| !is_file_excluded(path, &resolver));\n        if paths.is_empty() {\n            return Ok((vec![], resolver));\n        }\n    }\n\n    let (first_path, rest_paths) = paths\n        .split_first()\n        .ok_or_else(|| anyhow!(\"Expected at least one path to search for Python files\"))?;\n    // Create the `WalkBuilder`.\n    let mut builder = WalkBuilder::new(first_path);\n\n    if let Ok(cwd) = std::env::current_dir() {\n        builder.current_dir(cwd);\n    }\n\n    for path in rest_paths {\n        builder.add(path);\n    }\n    builder.standard_filters(resolver.respect_gitignore());\n    builder.hidden(false);\n\n    builder.threads(\n        std::thread::available_parallelism()\n            .map_or(1, std::num::NonZeroUsize::get)\n            .min(12),\n    );","sourceCodeStart":460,"sourceCodeEnd":496,"githubUrl":"https://github.com/astral-sh/ruff/blob/672bb4edf04c84f8b0753346359daee4057158f2/crates/ruff_workspace/src/resolver.rs#L460-L496","documentation":"Guard inside `project_files_in_path` (crates/ruff_workspace/src/resolver.rs:429), the shared entry point ruff and ty use to walk paths for Python files. After normalizing and deduplicating the input slice, the function needs a first path to seed `ignore::WalkBuilder`; an empty slice violates that invariant and is converted into this anyhow error. Note that the `force-exclude` branch just above returns `Ok((vec![], resolver))` early when exclusions remove everything, so only a caller that passes zero paths up front can actually reach it.","triggerScenarios":"Calling `ruff_workspace::resolver::project_files_in_path(&[], &pyproject_config, &transformer)` with an empty path slice — typically because an upstream glob or filter removed every entry before the call. The bundled CLIs always default to `.`, so end users of `ruff`/`ty` effectively never see this.","commonSituations":"Editor integrations or custom runners built on ruff_workspace that compute the file set themselves (empty workspace, empty glob result, or all candidate paths pre-filtered out) and forward the empty Vec unchanged.","solutions":["Default the path list to the current directory when your collection step yields nothing: `if paths.is_empty() { paths.push(std::env::current_dir()?); }`","Log `paths.len()` immediately before the call to find which upstream filter emptied it and fix that filter","If you only need CLI behavior, shell out to `ruff check .` / `ty check .` instead of calling the function directly"],"exampleFix":"// before\nlet files = project_files_in_path(&paths, &pyproject_config, &transformer)?; // paths == vec![]\n\n// after\nlet paths = if paths.is_empty() {\n    vec![std::env::current_dir()?]\n} else {\n    paths\n};\nlet files = project_files_in_path(&paths, &pyproject_config, &transformer)?;","handlingStrategy":"validation","validationCode":"if paths.is_empty() {\n    anyhow::bail!(\"no paths to search: refusing to call project_files_in_path\");\n}","typeGuard":null,"tryCatchPattern":"let result = project_files_in_path(&paths, &cfg, &transformer);\nif let Err(e) = &result {\n    if e.to_string().contains(\"Expected at least one path\") {\n        // caller bug: fix the empty input; do not retry\n    }\n}","preventionTips":["Never pass an empty path slice; default to the current directory when your filter empties the set","Compute and validate the file set before calling into ruff_workspace","Treat this message as an assertion failure in your glue code, not an environmental error to retry"],"tags":["rust","ruff","file-discovery","empty-input","api-misuse"],"backgroundTag":null,"analyzedSha":"672bb4edf04c84f8b0753346359daee4057158f2","analyzedAt":"2026-08-16T08:54:05.464Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}