felixse/FluentTerminal · critical · Win32Exception

Could not get console mode.

Error message

Could not get console mode.

What it means

Thrown by Terminal.EnableVirtualTerminalSequenceProcessing when GetConsoleMode() returns false for the console screen-buffer handle. Before enabling VT processing the code queries the current console mode flags; if that query fails the Win32 error is wrapped and thrown, aborting terminal startup.

Source

Thrown at FluentTerminal.SystemTray/Services/ConPty/Terminal.cs:72

            var windowHandle = GetConsoleWindow();
            ShowWindow(windowHandle, SW_HIDE);

            // And enable VT processing for our process's console.
            EnableVirtualTerminalSequenceProcessing();
        }

        ~Terminal()
        {
            Dispose(false);
        }

        private void EnableVirtualTerminalSequenceProcessing()
        {
            SafeFileHandle screenBuffer = GetConsoleScreenBuffer();
            if (!GetConsoleMode(screenBuffer, out uint outConsoleMode))
            {
                throw new Win32Exception(Marshal.GetLastWin32Error(), $"Could not get console mode.");
            }
            outConsoleMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING | DISABLE_NEWLINE_AUTO_RETURN;

            if (!SetConsoleMode(screenBuffer, outConsoleMode))
            {
                throw new Win32Exception(Marshal.GetLastWin32Error(), $"Could not enable virtual terminal processing.");
            }
        }

        /// <summary>
        /// Start the psuedoconsole and run the process as shown in 
        /// https://docs.microsoft.com/en-us/windows/console/creating-a-pseudoconsole-session#creating-the-pseudoconsole
        /// </summary>
        /// <param name="command">the command to run, e.g. cmd.exe</param>
        /// <param name="consoleHeight">The height (in characters) to start the pseudoconsole with. Defaults to 80.</param>
        /// <param name="consoleWidth">The width (in characters) to start the pseudoconsole with. Defaults to 30.</param>
        public void Start(string command, string directory, string environment, int consoleWidth = 80, int consoleHeight = 30)
        {

View on GitHub (pinned to ba83ec485e)

Solutions

  1. Inspect Win32Exception.NativeErrorCode (e.g. ERROR_INVALID_HANDLE) to confirm a stale/invalid handle.
  2. Ensure GetConsoleScreenBuffer succeeded and the handle is fresh before querying mode.
  3. Run the tray process in an interactive desktop session with a real console.
  4. Fall back to the WinPty backend if ConPty cannot initialize on this Windows build.

Example fix

// before
if (!GetConsoleMode(screenBuffer, out uint outConsoleMode))
    throw new Win32Exception(Marshal.GetLastWin32Error(), $"Could not get console mode.");

// after
int err = Marshal.GetLastWin32Error();
throw new Win32Exception(err, $"Could not get console mode (Win32 error {err}).");
Defensive patterns

Strategy: try-catch

Validate before calling

// Verify the screen-buffer handle is valid before querying mode.
var sb = GetConsoleScreenBuffer();
if (sb.IsInvalid || sb.IsClosed) throw new InvalidOperationException("console screen buffer handle invalid");

Try / catch

try { terminal = new Terminal(); }
catch (System.ComponentModel.Win32Exception ex) when (ex.Message.Contains("console mode")) { logger.Error(ex, $"GetConsoleMode failed (Win32 {ex.NativeErrorCode})"); fallbackToWinPty(); }

Prevention

When it happens

Trigger: Calling EnableVirtualTerminalSequenceProcessing (from the Terminal ctor) when the screen-buffer handle obtained from GetConsoleScreenBuffer is invalid or already closed, so GetConsoleMode cannot read the mode.

Common situations: Console screen buffer was closed/invalidated between allocation and mode query; running in an environment where the CONOUT$ handle is not backed by a real console (remote/service sessions); handle became stale.

Related errors


AI-assisted analysis of felixse/FluentTerminal@ba83ec485e (2026-08-13). Data as JSON: /api/errors/d3542c68ac63268a. Report an issue: GitHub.