denoland/deno · error
Windows file names may not contain `"` or end with `\`
Error message
Windows file names may not contain `"` or end with `\`
What it means
Batch files (.bat/.cmd) are launched by wrapping the entire command line in an extra quoted cmd.exe /c "..." sequence. A script path containing a double quote would break out of that quoting, and one ending with a backslash would escape the closing quote, so both are rejected with InvalidInput before the command line is assembled.
Source
Thrown at runtime/subprocess_windows/src/process.rs:1487
// Copyright The Rust Project Contributors - MIT
fn make_bat_command_line(
script: &[u16],
args: &[&OsStr],
force_quotes: bool,
) -> io::Result<Vec<u16>> {
// Set the start of the command line to `cmd.exe /c "`
// It is necessary to surround the command in an extra pair of quotes,
// hence the trailing quote here. It will be closed after all arguments
// have been added.
// Using /e:ON enables "command extensions" which is essential for the `%` hack to work.
let mut cmd: Vec<u16> = "/e:ON /v:OFF /d /c \"".encode_utf16().collect();
// Push the script name surrounded by its quote pair.
cmd.push(b'"' as u16);
// Windows file names cannot contain a `"` character or end with `\\`.
// If the script name does then return an error.
if script.contains(&(b'"' as u16)) || script.last() == Some(&(b'\\' as u16)) {
return Err(std::io::Error::new(
io::ErrorKind::InvalidInput,
"Windows file names may not contain `\"` or end with `\\`",
));
}
cmd.extend_from_slice(script.strip_suffix(&[0]).unwrap_or(script));
cmd.push(b'"' as u16);
// Append the arguments.
// FIXME: This needs tests to ensure that the arguments are properly
// reconstructed by the batch script by default.
for arg in args.iter().skip(1) {
cmd.push(' ' as u16);
let arg_bytes = arg.as_encoded_bytes();
// Disallow \r and \n as they may truncate the arguments.
const DISALLOWED: &[u8] = b"\r\n";
if arg_bytes.iter().any(|c| DISALLOWED.contains(c)) {
return Err(std::io::Error::new(
io::ErrorKind::InvalidInput,View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Build paths with a join helper instead of concatenation so no trailing backslash remains
- Reject or strip double quotes in batch script paths before spawning
- Rename the offending file - Windows itself forbids quotes in filenames, so such a path almost always indicates an upstream bug
Example fix
// before - path ends with a backslash before quoting is applied
const c = new Deno.Command(`C:\\tools\\${name}.cmd\\`);
// after
import { join } from "jsr:@std/path";
const c = new Deno.Command(join("C:/tools", `${name}.cmd`)); Defensive patterns
Strategy: validation
Validate before calling
const isSafeWindowsScriptPath = (p: string) =>
!p.includes('"') && !p.endsWith("\\");
if (/\.(bat|cmd)$/i.test(prog) && !isSafeWindowsScriptPath(prog)) {
throw new Error(`unsafe batch script path: ${prog}`);
} Type guard
const isSafeScriptPath = (p: string): p is string =>
!p.includes('"') && !p.endsWith("\\"); Prevention
- Build Windows paths with a join helper, never raw concatenation
- Reject quote characters in any path that reaches spawn
- Validate config-driven script paths at load time, not at spawn time
When it happens
Trigger: Spawning a .bat/.cmd file whose resolved path contains a " character or ends with a backslash - e.g. new Deno.Command("C:\\tools\\setup.cmd\\") or a path built from unvalidated user input that includes a quote.
Common situations: Paths assembled by string concatenation that keep a trailing separator; filenames containing quotes (extracted from archives or user input); config-driven script paths that were never validated before spawn.
Related errors
- nul byte found in provided data
- batch file arguments are invalid
- {}: ({}) {}
- failed to unregister: {}
- the source and destination are the same file
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/e44331b6b70f60cd.
Report an issue: GitHub.