felixse/FluentTerminal · critical · Exception

winpty_error_msg(errorHandle)

Error message

winpty_error_msg(errorHandle)

What it means

Thrown by WinPtySession.Start when winpty_open (the call that creates the winpty agent process) returns a non-null errorHandle. The winpty_error_msg(errorHandle) call extracts the human-readable error string from that handle; the message you see is winpty's own diagnostic for why the pseudoconsole could not be opened.

Source

Thrown at FluentTerminal.SystemTray/Services/WinPty/WinPtySession.cs:42

        {
            _enableBuffer = false; // request.Profile.UseBuffer;

            Id = request.Id;
            _terminalsManager = terminalsManager;

            var configHandle = IntPtr.Zero;
            var spawnConfigHandle = IntPtr.Zero;
            var errorHandle = IntPtr.Zero;

            try
            {
                configHandle = winpty_config_new(WINPTY_FLAG_COLOR_ESCAPES, out errorHandle);
                winpty_config_set_initial_size(configHandle, request.Size.Columns, request.Size.Rows);

                _handle = winpty_open(configHandle, out errorHandle);
                if (errorHandle != IntPtr.Zero)
                {
                    throw new Exception(winpty_error_msg(errorHandle));
                }

                var cwd = GetWorkingDirectory(request.Profile);
                var args = request.Profile.Arguments;

                if (!string.IsNullOrWhiteSpace(request.Profile.Location))
                {
                    args = $"\"{request.Profile.Location}\" {args}";
                }

                spawnConfigHandle = winpty_spawn_config_new(WINPTY_SPAWN_FLAG_AUTO_SHUTDOWN, request.Profile.Location, args, cwd, terminalsManager.GetDefaultEnvironmentVariableString(request.Profile.EnvironmentVariables), out errorHandle);
                if (errorHandle != IntPtr.Zero)
                {
                    throw new Exception(winpty_error_msg(errorHandle));
                }

                _stdin = CreatePipe(winpty_conin_name(_handle), PipeDirection.Out);
                _stdout = CreatePipe(winpty_conout_name(_handle), PipeDirection.In);

View on GitHub (pinned to ba83ec485e)

Solutions

  1. Verify winpty.dll and winpty-agent.exe are deployed alongside the app and match the process architecture (x64).
  2. Check the winpty_error_msg text for the exact OS-level reason and address it (missing DLL, access denied).
  3. Whitelist the agent in antivirus/EDR if it is being blocked.
  4. Fall back to the ConPty backend on Windows 10 1809+ where winpty is not required.

Example fix

// before
_handle = winpty_open(configHandle, out errorHandle);
if (errorHandle != IntPtr.Zero)
    throw new Exception(winpty_error_msg(errorHandle));

// after - wrap with context
throw new Exception($"winpty_open failed: {winpty_error_msg(errorHandle)}. Ensure winpty.dll and winpty-agent.exe match the process architecture.");
Defensive patterns

Strategy: try-catch

Validate before calling

// Verify winpty binaries are present and correct architecture before starting.
if (!File.Exists(Path.Combine(appDir, "winpty.dll")) || !File.Exists(Path.Combine(appDir, "winpty-agent.exe")))
    throw new DllNotFoundException("winpty.dll/winpty-agent.exe missing");

Try / catch

try { session.Start(request, manager); }
catch (Exception ex) { logger.Error(ex, "winpty_open failed"); fallbackToConPty(); }

Prevention

When it happens

Trigger: After winpty_config_new and set_initial_size, winpty_open fails: winpty.dll/winpty-agent.exe are missing or the wrong architecture, the agent could not be spawned, or a previous handle leaked. errorHandle != IntPtr.Zero selects this branch.

Common situations: Bundled winpty binaries are missing, mismatched architecture (x86 vs x64), or wrong bitness for the process; agent executable blocked by antivirus; insufficient privileges to spawn the agent.

Related errors


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