denoland/deno · error · anyhow::Error

Invalid file path '{}'

Error message

Invalid file path '{}'

What it means

Shared helper that converts a filesystem Path into a `file://` ModuleSpecifier. `ModuleSpecifier::from_file_path` rejects paths that cannot form a valid file URL — empty paths and non-UTF-8 byte sequences — and the failure is re-wrapped with the offending path printed.

Source

Thrown at cli/util/fs.rs:179

/// Gets the total size (in bytes) of a directory.
pub fn dir_size(path: &Path) -> std::io::Result<u64> {
  let entries = std::fs::read_dir(path)?;
  let mut total = 0;
  for entry in entries {
    let entry = entry?;
    total += match entry.metadata()? {
      data if data.is_dir() => dir_size(&entry.path())?,
      data => data.len(),
    };
  }
  Ok(total)
}

pub fn specifier_from_file_path(
  path: &Path,
) -> Result<ModuleSpecifier, AnyError> {
  ModuleSpecifier::from_file_path(path)
    .map_err(|_| anyhow!("Invalid file path '{}'", path.display()))
}

#[derive(Default)]
pub struct FsCleaner {
  pub files_removed: u64,
  pub dirs_removed: u64,
  pub bytes_removed: u64,
  /// Paths that could not be removed, along with the error encountered. The
  /// cleaner is best-effort: a single locked or read-only file (for example a
  /// cache database held open by a running Deno process) should not abort the
  /// entire clean, so failures are collected here and reported afterwards.
  pub failed: Vec<(PathBuf, std::io::Error)>,
  pub progress_guard: Option<UpdateGuard>,
}

impl FsCleaner {
  pub fn new(progress_guard: Option<UpdateGuard>) -> Self {
    Self {

View on GitHub (pinned to 89f33cbef2)

Solutions

  1. Validate the path is non-empty and valid UTF-8 before conversion (`path.to_str().is_some()`)
  2. Reject or canonicalize user-supplied paths earlier in the pipeline so only well-formed paths reach this helper
  3. Avoid constructing paths from lossy (`to_string_lossy`) output, which can smuggle in replacement characters

Example fix

// before
let spec = specifier_from_file_path(&PathBuf::from(user_input))?;
// after
let p = PathBuf::from(user_input);
if p.as_os_str().is_empty() || p.to_str().is_none() {
  return Err(anyhow!("path is empty or not valid UTF-8"));
}
let spec = specifier_from_file_path(&p)?;
Defensive patterns

Strategy: type-guard

Validate before calling

// Rust: check before converting
fn is_urlable_path(p: &Path) -> bool {
  !p.as_os_str().is_empty() && p.to_str().is_some()
}

if is_urlable_path(&path) {
  let spec = specifier_from_file_path(&path)?;
}

Type guard

fn is_urlable_path(p: &Path) -> bool {
  !p.as_os_str().is_empty() && p.to_str().is_some()
}

Try / catch

// Rust: catch and add caller context
match specifier_from_file_path(&path) {
  Ok(spec) => spec,
  Err(e) if e.to_string().contains("Invalid file path") => {
    return Err(anyhow::anyhow!("skipping non-URL-able path {}: {e}", path.display()));
  }
  Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling `specifier_from_file_path` (used across CLI tooling) with `Path::new("")` or a path containing invalid UTF-8 on Unix.

Common situations: Embedder/library code passing user input straight to PathBuf; paths produced by lossy string conversions; missing empty-input filtering before the call.

Related errors


AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16). Data as JSON: /api/errors/b3ff80577f282603. Report an issue: GitHub.