denoland/deno · error
Invalid handle
Error message
Invalid handle
What it means
During spawn, each stdio slot carrying a raw handle is duplicated into the child with DuplicateHandle. uv_duplicate_handle() first rejects obviously broken values - INVALID_HANDLE_VALUE (-1), NULL, and the -2 sentinel - with InvalidInput 'Invalid handle', because duplicating them would fail or hand the child a garbage stream.
Source
Thrown at runtime/subprocess_windows/src/process_stdio.rs:174
unsafe {
copy_handle(
child_stdio_handle(buffer, fd)
.cast::<HANDLE>()
.read_unaligned(),
&mut handle,
)
};
handle
}
pub unsafe fn uv_duplicate_handle(
handle: HANDLE,
) -> Result<HANDLE, std::io::Error> {
if handle == INVALID_HANDLE_VALUE
|| handle.is_null()
|| handle == ((-2i32) as usize as HANDLE)
{
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"Invalid handle",
));
}
let mut dup = INVALID_HANDLE_VALUE;
let current_process = unsafe { GetCurrentProcess() };
if unsafe {
DuplicateHandle(
current_process,
handle,
current_process,
&mut dup,
0,
1,
DUPLICATE_SAME_ACCESS,
)View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Use supported stdio actions ("pipe", "inherit", "null") instead of raw handles
- Ensure any stream or resource passed via stdio is still open at spawn time
- Validate handles are not null, -1, or -2 before building the stdio vector
Defensive patterns
Strategy: validation
Validate before calling
function isValidHandle(h: number | null): boolean {
return typeof h === "number" && h !== 0 && h !== -1 && h !== -2;
}
// validate every raw stdio handle before building the spawn options Type guard
const isValidRawHandle = (h: unknown): h is number => typeof h === "number" && h !== 0 && h !== -1 && h !== -2;
Prevention
- Prefer stdio actions ("pipe"/"inherit"/"null") over raw handles
- Spawn immediately after acquiring streams, before anything can close them
- Never substitute sentinel values (-1/0) for unknown fds in stdio config
When it happens
Trigger: Passing a closed, null, or sentinel handle in the stdio vector of a spawn: a resource already closed before spawn, an fd of -1 or 0 coming from config defaults, or code that treats Unix fd numbers as Windows handles.
Common situations: Forwarding request/server streams or inherited fds that were closed before the child started; mixing libuv handle values with plain integers; sanitization code that substitutes unknown fds with -1.
Related errors
- Invalid stdio count
- GetHandleInformation failed (error {})
- Could not open NUL device (error {})
- SetStdHandle failed (error {})
- {}: ({}) {}
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/dcbfe924a1e4b07a.
Report an issue: GitHub.