From 352fa24e7ff250de0bc700c3f33054c285cb1180 Mon Sep 17 00:00:00 2001 From: Joel-Wwalker Date: Fri, 17 Jul 2026 03:38:10 -0400 Subject: [PATCH 1/2] Windows: add context when opening NUL for child stdio fails A failed open of \\.\NUL for Stdio::Null surfaced as a bare OS error (usually NotFound), which reads as if the spawned program is missing. Wrap it with the operation and stream name, preserving the ErrorKind. --- library/std/src/sys/process/windows.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/process/windows.rs b/library/std/src/sys/process/windows.rs index a747ef048d901..c4f41bf634ce7 100644 --- a/library/std/src/sys/process/windows.rs +++ b/library/std/src/sys/process/windows.rs @@ -640,7 +640,21 @@ impl Stdio { opts.read(stdio_id == c::STD_INPUT_HANDLE); opts.write(stdio_id != c::STD_INPUT_HANDLE); opts.inherit_handle(true); - File::open(Path::new(r"\\.\NUL"), &opts).map(|file| file.into_inner()) + File::open(Path::new(r"\\.\NUL"), &opts).map(|file| file.into_inner()).map_err( + |e| { + // A raw `NotFound` here is easily mistaken for the program + // being missing, so say what actually failed to open. + let stream = match stdio_id { + c::STD_INPUT_HANDLE => "stdin", + c::STD_OUTPUT_HANDLE => "stdout", + _ => "stderr", + }; + Error::new( + e.kind(), + format!("failed to open NUL device for child {stream}: {e}"), + ) + }, + ) } } } From d9ac1a5bc7c9eb680130a0d47efe9d5a1e3049d0 Mon Sep 17 00:00:00 2001 From: Joel-Wwalker Date: Sat, 18 Jul 2026 07:20:46 -0400 Subject: [PATCH 2/2] Print unknown stdio ids instead of assuming stderr in the NUL error --- library/std/src/sys/process/windows.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/library/std/src/sys/process/windows.rs b/library/std/src/sys/process/windows.rs index c4f41bf634ce7..0cff0fb7945c4 100644 --- a/library/std/src/sys/process/windows.rs +++ b/library/std/src/sys/process/windows.rs @@ -644,10 +644,13 @@ impl Stdio { |e| { // A raw `NotFound` here is easily mistaken for the program // being missing, so say what actually failed to open. + // `spawn` only passes the three standard ids, but print + // anything else as a number rather than mislabeling it. let stream = match stdio_id { - c::STD_INPUT_HANDLE => "stdin", - c::STD_OUTPUT_HANDLE => "stdout", - _ => "stderr", + c::STD_INPUT_HANDLE => "stdin".to_string(), + c::STD_OUTPUT_HANDLE => "stdout".to_string(), + c::STD_ERROR_HANDLE => "stderr".to_string(), + id => format!("stdio handle {id}"), }; Error::new( e.kind(),