denoland/deno · error

File not found

Error message

File not found

What it means

Before CreateProcessW runs, Deno locates the executable with search_path(), using the child's cwd and the PATH from the child environment (or an overridden one) plus Windows extension rules. If no matching executable is found, spawn fails with ErrorKind::NotFound 'File not found', mirroring libuv behavior on Windows.

Source

Thrown at runtime/subprocess_windows/src/process.rs:606

  let path = child_paths
    .map(|p| p.encode_wide().chain(Some(0)).collect::<Vec<_>>())
    .or_else(|| {
      // PATH not found in provided environment, get system PATH
      std::env::var_os("PATH")
        .map(|p| p.encode_wide().chain(Some(0)).collect::<Vec<_>>())
    });

  // Create and set up stdio
  let child_stdio_buffer = uv_stdio_create(options)?;

  // Search for the executable
  let Some(application_path) = search_path(
    application.as_slice_no_nul(),
    cwd.as_slice_no_nul(),
    path.as_deref(),
    options.flags,
  ) else {
    return Err(std::io::Error::new(
      std::io::ErrorKind::NotFound,
      "File not found",
    ));
  };

  // Create command line arguments
  let args: Vec<&OsStr> = options.args.iter().map(|s| s.as_ref()).collect();
  let verbatim_arguments =
    (options.flags & uv_process_flags::WindowsVerbatimArguments) != 0;

  let has_bat_extension = |program: &[u16]| {
    // lifted from https://github.com/rust-lang/rust/blob/bc1d7273dfbc6f8a11c0086fa35f6748a13e8d3c/library/std/src/sys/process/windows.rs#L284
    // Copyright The Rust Project Contributors - MIT
    matches!(
      // Case insensitive "ends_with" of UTF-16 encoded ".bat" or ".cmd"
      program.len().checked_sub(4).and_then(|i| program.get(i..)),
      Some(
        [46, 98 | 66, 97 | 65, 116 | 84] | [46, 99 | 67, 109 | 77, 100 | 68]

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. When passing a custom env, merge it with the parent's: env: { ...Deno.env.toObject(), ...overrides }
  2. Use an absolute path to the executable, including the .exe/.cmd extension on Windows
  3. Install the dependency or add its directory to PATH before spawning
  4. Catch Deno.errors.NotFound and report which program and PATH were used

Example fix

// before - custom env drops PATH, executable lookup fails
const c = new Deno.Command("ffmpeg", { env: { FOO: "1" } });

// after - keep PATH while overriding only what you need
const c = new Deno.Command("ffmpeg", {
  env: { ...Deno.env.toObject(), FOO: "1" },
});
Defensive patterns

Strategy: try-catch

Validate before calling

function findOnPath(prog: string, path = Deno.env.get("PATH") ?? ""): string | null {
  for (const dir of path.split(";")) {
    for (const ext of ["", ".exe", ".cmd", ".bat"]) {
      const p = `${dir}/${prog}${ext}`;
      try {
        if (Deno.statSync(p).isFile) return p;
      } catch { /* keep scanning */ }
    }
  }
  return null;
}
const exe = findOnPath(prog); // null -> fail with a clear message before spawn

Try / catch

try {
  const child = cmd.spawn();
} catch (err) {
  if (err instanceof Deno.errors.NotFound) {
    console.error(`"${prog}" not found on PATH`);
    Deno.exit(1);
  }
  throw err;
}

Prevention

When it happens

Trigger: new Deno.Command("tool").spawn() on Windows where tool / tool.exe / tool.cmd / tool.bat is not on PATH; passing a custom env object that omits PATH so the lookup has nothing to search; a misspelled program or wrong extension; an incorrect cwd option.

Common situations: The dependency (git, ffmpeg, magick) is not installed on Windows; replacing env with a literal object and losing PATH; CI or service accounts with a minimal PATH; Unix-first scripts assuming extension-less binary lookup.

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/759973ad19726ca6. Report an issue: GitHub.