denoland/deno · error
GetHandleInformation failed (error {})
Error message
GetHandleInformation failed (error {}) What it means
During early startup on Windows, Deno probes stdin/stdout/stderr with GetStdHandle + GetHandleInformation to detect closed handles and substitute the NUL device. If GetHandleInformation fails with any error other than ERROR_INVALID_HANDLE, the handle state is too broken to recover from and Deno panics with the raw Win32 error code. It means a handle exists but its flags cannot be queried (access denied, bogus inherited handle).
Source
Thrown at cli/util/windows.rs:223
use windows_sys::Win32::Storage::FileSystem::OPEN_EXISTING;
use windows_sys::Win32::System::Console::GetStdHandle;
use windows_sys::Win32::System::Console::STD_ERROR_HANDLE;
use windows_sys::Win32::System::Console::STD_INPUT_HANDLE;
use windows_sys::Win32::System::Console::STD_OUTPUT_HANDLE;
use windows_sys::Win32::System::Console::SetStdHandle;
for std_handle in [STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE] {
// Check whether stdio handle is open.
let handle = GetStdHandle(std_handle);
let is_valid = if handle.is_null() || handle == INVALID_HANDLE_VALUE {
false
} else {
// The stdio handle is open; check whether its handle is valid.
let mut flags: u32 = 0;
match GetHandleInformation(handle, &mut flags) {
FALSE if GetLastError() == ERROR_INVALID_HANDLE => false,
FALSE => {
panic!("GetHandleInformation failed (error {})", GetLastError());
}
_ => true,
}
};
if !is_valid {
// Open NUL device.
let desired_access = match std_handle {
STD_INPUT_HANDLE => FILE_GENERIC_READ,
_ => FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES,
};
let security_attributes = SECURITY_ATTRIBUTES {
nLength: size_of::<SECURITY_ATTRIBUTES>() as u32,
lpSecurityDescriptor: std::ptr::null_mut(),
bInheritHandle: TRUE,
};
let file_handle = CreateFileA(
c"\\\\?\\NUL".as_ptr() as *const u8,View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Launch Deno from a normal console to verify it works there
- When spawning Deno programmatically, always pass explicit stdin/stdout/stderr (pipe, file, or NUL) instead of inheriting broken handles
- Use explicit redirection in service contexts: `deno run app.ts < NUL > deno.log 2>&1`
- Translate the reported code with `net helpmsg <code>` to identify which handle/query failed; report to denoland/deno if it persists on the latest version
Example fix
:: before — scheduler/service launches deno with broken inherited stdio deno run app.ts :: after — every stream gets a valid target deno run app.ts < NUL > deno.log 2>&1
Defensive patterns
Strategy: validation
Validate before calling
// Rust parent: never leave deno with broken inherited handles
use std::process::{Command, Stdio};
Command::new("deno")
.args(["run", "app.ts"])
.stdin(Stdio::null())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()?; Prevention
- Always pass explicit stdio (pipe/file/NUL) when spawning Deno from services, schedulers, or CI agents
- Avoid launching Deno with closed inherited handle slots
- Note the Win32 code in the message and decode it with `net helpmsg <code>` before reporting
When it happens
Trigger: Launching `deno` from a parent that passes broken or pseudo stdio handles: Windows services, Task Scheduler, git hooks, CI agents, or hand-rolled CreateProcess callers that close or redirect stdio incorrectly; also security software intercepting handle queries.
Common situations: Running Deno as a scheduled task or service without explicit stdio redirection; spawning Deno from another program with closed handle slots; antivirus/EDR interference on Windows.
Related errors
- Could not open NUL device (error {})
- SetStdHandle failed (error {})
- Invalid handle
- Invalid stdio count
- Cannot serve HTTP requests: either a `handler` or `options`
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/b1d8afd2ebd1f5b7.
Report an issue: GitHub.