wezterm/wezterm · error

SetConsoleMode failed: {}

Error message

SetConsoleMode failed: {}

What it means

On Windows, InputHandle::set_input_mode calls SetConsoleMode on the console input handle to install the mode flags termwiz needs (raw input, virtual terminal input, etc.). The API returns 0 on failure and the code bails with GetLastError(). It fails when the handle is not a console input handle, is closed, or the mode bits are invalid for that handle type.

Source

Thrown at termwiz/src/terminal/windows.rs:92

        dy: i16,
        attr: u16,
    ) -> Result<()>;
}

struct InputHandle {
    handle: FileDescriptor,
}

impl Read for InputHandle {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
        self.handle.read(buf)
    }
}

impl ConsoleInputHandle for InputHandle {
    fn set_input_mode(&mut self, mode: u32) -> Result<()> {
        if unsafe { SetConsoleMode(self.handle.as_raw_handle(), mode) } == 0 {
            bail!("SetConsoleMode failed: {}", IoError::last_os_error());
        }
        Ok(())
    }

    fn get_input_mode(&mut self) -> Result<u32> {
        let mut mode = 0;
        if unsafe { GetConsoleMode(self.handle.as_raw_handle(), &mut mode) } == 0 {
            bail!("GetConsoleMode failed: {}", IoError::last_os_error());
        }
        Ok(mode)
    }

    fn set_input_cp(&mut self, cp: u32) -> Result<()> {
        if unsafe { SetConsoleCP(cp) } == 0 {
            bail!("SetConsoleCP failed: {}", IoError::last_os_error());
        }
        Ok(())
    }

View on GitHub (pinned to b99b1ca2cc)

Solutions

  1. Run with stdin attached to a real console (interactive cmd/PowerShell/Windows Terminal)
  2. Verify the handle is a console before entering raw mode: call GetConsoleMode first; if it fails, redirect scenarios must be handled separately
  3. On Windows 10+ ensure the console supports VT; use Windows Terminal or ConPTY rather than legacy conhost
  4. When stdin is not a console, use a pty layer (ConPTY / portable-pty) instead of the console APIs
Defensive patterns

Strategy: validation

Validate before calling

// probe whether stdin is a console before touching console modes
let mut mode = 0u32;
let is_console = unsafe {
    consoleapi::GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE) as *mut _, &mut mode)
} != 0;
if !is_console { /* use non-console input path */ }

Type guard

fn is_console_handle(handle: HANDLE) -> bool {
    let mut mode = 0u32;
    unsafe { consoleapi::GetConsoleMode(handle as *mut _, &mut mode) } != 0
}

Try / catch

if let Err(e) = input.set_input_mode(mode) {
    if !is_console_handle(handle) {
        // stdin is redirected: fall back to plain stream reading
        return setup_non_console_input();
    }
    return Err(e);
}

Prevention

When it happens

Trigger: Entering raw mode / setting input modes when stdin is redirected (pipe or file instead of the console), when the console handle was closed, when the process has no attached console (some service/session setups), or when invalid mode flag combinations are passed.

Common situations: Running a termwiz/wezterm-based TUI with stdin redirected (`app < file`), under CI on Windows without a console, detached services, or legacy consoles where VT input flags (ENABLE_VIRTUAL_TERMINAL_INPUT) are unsupported.

Related errors


AI-assisted analysis of wezterm/wezterm@b99b1ca2cc (2026-09-05). Data as JSON: /api/errors/f9206751656d5223. Report an issue: GitHub.