astral-sh/ruff · error

project directory ` ` does not contain a base name

Error message

project directory `{project_path}` does not contain a base name

What it means

Task::new in ty_completion_eval requires the project directory path to end with a real directory name. It calls SystemPath::file_name() and fails when the path is empty or terminates in `..` or `/` with no final component, because the directory name is used as the human-readable task name.

Solutions

  1. Point the task's project_path at the actual fixture directory (e.g. crates/ty_completion_eval/truth/<fixture>), not the root or a parent
  2. Remove any trailing `..` or `/` segments from the configured path
  3. Use SystemPath::from_path with an absolute, non-root directory path and verify file_name() succeeds before calling Task::new

Example fix

// before
let task = Task::new(&SystemPath::from("..").unwrap(), &truth, cursor)?;
// after
let project = std::path::PathBuf::from("crates/ty_completion_eval/truth/my-project").canonicalize()?;
let task = Task::new(&SystemPath::from_std_path(&project).unwrap(), &truth, cursor)?;
Defensive patterns

Strategy: validation

Validate before calling

fn validate_project_path(p: &SystemPath) -> Result<(), String> {
    match p.file_name() {
        Some(_) if p.as_std_path().is_dir() => Ok(()),
        Some(_) => Err(format!("`{}` is not a directory", p.display())),
        None => Err(format!("`{}` has no base name (empty, root, or `..`)", p.display())),
    }
}

Type guard

fn has_base_name(p: &SystemPath) -> bool {
    p.file_name().is_some()
}

Try / catch

match Task::new(&project_path, &truth, cursor) {
    Ok(task) => run(task),
    Err(e) if e.to_string().contains("does not contain a base name") => {
        eprintln!("project_path must be a concrete fixture directory: {e}");
        std::process::exit(2);
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling Task::new with a SystemPath built from "/", ".", "foo/..", or a path that normalizes to the filesystem root; also paths constructed by joining that end with a trailing separator resolving to root.

Common situations: A completion-evaluation task CSV or fixture path is misconfigured to point at the repository root or a parent directory; a path was built with an erroneous trailing `..`; an empty path from environment/config substitution.

Related errors


AI-assisted analysis of astral-sh/ruff@5bb508f594 (2026-09-05). Data as JSON: /api/errors/09eb205e7c3ed90d. Report an issue: GitHub.

Appendix: source

Thrown at crates/ty_completion_eval/src/main.rs:277

    db: ProjectDatabase,
    dir: SystemPathBuf,
    name: String,
    cursor: Cursor,
    settings: ty_ide::CompletionSettings,
}

impl Task {
    /// Create a new task for the Python project at `project_path`.
    ///
    /// `truth` should correspond to the completion configuration and the
    /// expected answer for completions at the given `cursor` position.
    fn new(
        project_path: &SystemPath,
        truth: &CompletionTruth,
        cursor: Cursor,
    ) -> anyhow::Result<Task> {
        let name = project_path.file_name().ok_or_else(|| {
            anyhow::anyhow!("project directory `{project_path}` does not contain a base name")
        })?;

        let system = OsSystem::new(project_path);
        let mut project_metadata = ProjectMetadata::discover(project_path, &system)?;
        // Explicitly point ty to the .venv to avoid any set VIRTUAL_ENV variable to take precedence.
        project_metadata.set_override_options(Options {
            environment: Some(EnvironmentOptions {
                python: Some(RelativePathBuf::cli(".venv")),
                ..EnvironmentOptions::default()
            }),
            ..Options::default()
        });
        let db = ProjectDatabase::fallible(project_metadata, system)?;
        Ok(Task {
            db,
            dir: project_path.to_path_buf(),
            name: name.to_string(),
            cursor,

View on GitHub (pinned to 5bb508f594)