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
- When passing a custom env, merge it with the parent's: env: { ...Deno.env.toObject(), ...overrides }
- Use an absolute path to the executable, including the .exe/.cmd extension on Windows
- Install the dependency or add its directory to PATH before spawning
- 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
- Merge custom env with Deno.env.toObject() so PATH survives overrides
- Prefer absolute executable paths (with extension) on Windows
- Log the effective PATH when a spawn fails to speed up diagnosis
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
- nul byte found in provided data
- {}: ({}) {}
- failed to unregister: {}
- On Windows an `options` argument is required if the target d
- Process not found
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/759973ad19726ca6.
Report an issue: GitHub.