astral-sh/ruff · error

truth source directory

Error message

truth source directory `{dir}` does not contain a base name

What it means

TaskSource::new derives the source's name from the directory's base name via SystemPath::file_name(). This error is thrown when the truth source directory path has no final component (empty path or ends in `..`/root), because a deterministic name is required for the completion-evaluation task set.

Solutions

  1. Pass a concrete truth source subdirectory (one containing completion.toml), not the root or an empty path
  2. Check that the environment variable/argument supplying the truth directory is set and non-empty
  3. Canonicalize the directory and confirm file_name() is Some before constructing the TaskSource

Example fix

// before
let src = SystemPath::from(env::var("TRUTH_DIR").unwrap_or_default());
TaskSource::new(&src)?;
// after
let src = SystemPathBuf::from_path_buf(std::env::current_dir()?.join("crates/ty_completion_eval/truth/my-fixture")).unwrap();
assert!(src.file_name().is_some());
TaskSource::new(&src)?;
Defensive patterns

Strategy: validation

Validate before calling

fn validate_task_source(dir: &SystemPath) -> Result<(), String> {
    if dir.file_name().is_none() {
        return Err(format!("`{}` must be a named subdirectory", dir.display()));
    }
    if !dir.join("completion.toml").as_std_path().exists() {
        return Err(format!("`{}` is missing completion.toml", dir.display()));
    }
    Ok(())
}

Type guard

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

Try / catch

match TaskSource::new(&dir) {
    Ok(src) => src,
    Err(e) if e.to_string().contains("does not contain a base name") => {
        eprintln!("pass a concrete truth subdirectory, not the root: {e}");
        std::process::exit(2);
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling TaskSource::new with a SystemPath of "/", ".", "foo/.." or otherwise lacking a final component; typically reached through TaskSource::all only if a scan entry normalizes to such a path.

Common situations: A misconfigured truth root (empty TRUTH_DIR env var collapsing the join), or code passing the truth root itself instead of a child directory.

Related errors


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

Appendix: source

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

            let dir = SystemPath::from_std_path(&path).ok_or_else(|| {
                anyhow::anyhow!(
                    "truth source directory `{path}` contains invalid UTF-8",
                    path = path.display()
                )
            })?;
            sources.push(TaskSource::new(dir)?);
        }
        // Sort our sources so that we always run in the same order.
        // And also so that the CSV output is deterministic across
        // all platforms.
        sources.sort_by(|source1, source2| source1.name.cmp(&source2.name));
        Ok(sources)
    }

    fn new(dir: &SystemPath) -> anyhow::Result<TaskSource> {
        let name = dir.file_name().ok_or_else(|| {
            anyhow::anyhow!("truth source directory `{dir}` does not contain a base name")
        })?;

        let truth_path = dir.join("completion.toml");
        let truth_data = std::fs::read(truth_path.as_std_path())
            .with_context(|| format!("failed to read truth data at `{truth_path}`"))?;
        let truth = toml::from_slice(&truth_data).with_context(|| {
            format!("failed to parse TOML completion truth data from `{truth_path}`")
        })?;

        Ok(TaskSource {
            dir: dir.to_path_buf(),
            name: name.to_string(),
            truth,
        })
    }

    /// Convert this "source" task (from the Ruff repository) into
    /// one or more evaluation tasks within a single Python project.

View on GitHub (pinned to 5bb508f594)