felixse/FluentTerminal · critical · Win32Exception

Could not get console screen buffer.

Error message

Could not get console screen buffer.

What it means

Thrown by Terminal.GetConsoleScreenBuffer when CreateFileW on the console output pseudo-filename (CONOUT$) returns INVALID_HANDLE_VALUE (-1). This handle is needed to query/set console mode for VT processing even when STDOUT is redirected (e.g. by Visual Studio). A -1 return means the console screen buffer could not be opened.

Source

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

        /// A helper method that opens a handle on the console's screen buffer, which will allow us to get its output,
        /// even if STDOUT has been redirected (which Visual Studio does by default).
        /// </summary>
        /// <returns>A file handle to the console's screen buffer.</returns>
        /// <remarks>This is described in more detail here: https://docs.microsoft.com/en-us/windows/console/console-handles </remarks>
        private SafeFileHandle GetConsoleScreenBuffer()
        {
            IntPtr file = CreateFileW(
                ConsoleOutPseudoFilename,
                GENERIC_WRITE | GENERIC_READ,
                FILE_SHARE_WRITE,
                IntPtr.Zero,
                OPEN_EXISTING,
                FILE_ATTRIBUTE_NORMAL,
                IntPtr.Zero);

            if (file == new IntPtr(-1))
            {
                throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not get console screen buffer.");
            }

            return new SafeFileHandle(file, true);
        }

        #region IDisposable Support

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(true);
        }

        private bool alreadyDisposed = false;

        public void Dispose(bool disposeManaged)
        {
            if (alreadyDisposed)

View on GitHub (pinned to ba83ec485e)

Solutions

  1. Ensure AllocConsole succeeded (error 13) before GetConsoleScreenBuffer is reached - the ctor orders these correctly, so an allocation failure is the usual upstream cause.
  2. Inspect Win32Exception.NativeErrorCode (ERROR_INVALID_HANDLE / access denied).
  3. Run the tray process in an interactive session with a genuine console.
  4. Fall back to WinPty if ConPty cannot obtain the screen buffer.

Example fix

// before
if (file == new IntPtr(-1))
    throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not get console screen buffer.");

// after
int err = Marshal.GetLastWin32Error();
throw new Win32Exception(err, $"Could not get console screen buffer (Win32 error {err}). Ensure a console is allocated.");
Defensive patterns

Strategy: try-catch

Validate before calling

// Ensure a console exists before opening CONOUT$.
if (GetConsoleWindow() == IntPtr.Zero) AllocConsole();
var h = CreateFileW(ConsoleOutPseudoFilename, GENERIC_WRITE|GENERIC_READ, FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
if (h == new IntPtr(-1)) throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());

Try / catch

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

Prevention

When it happens

Trigger: Constructing a Terminal when there is no real console attached (so CONOUT$ does not resolve), or when GENERIC_WRITE|GENERIC_READ access is denied on the console. The check `file == new IntPtr(-1)` trips.

Common situations: AllocConsole failed or was skipped yet the code reaches here; running under a debugger/host that redirected all console handles; service/session without an interactive desktop console.

Related errors


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