microsoft/aspire · error · Win32Exception

Failed to invoke CloseHandle while starting tracked browser…

Error message

Failed to invoke CloseHandle while starting tracked browser CDP pipe.

What it means

The launcher closes OS handles for the tracked browser process and its thread via CloseHandle in CloseWindowsHandle, used during StartWindows. If CloseHandle returns FALSE for a non-zero handle, this Win32Exception-named error is thrown. It indicates a handle could not be released - usually a symptom of double-close or handle corruption.

Solutions

  1. Check the inner NativeErrorCode (ERROR_INVALID_HANDLE=6 usually means double-close).
  2. Look for code paths in the session that could close the same handles before the launcher's cleanup.
  3. Retry the browser launch - a leaked handle rarely affects subsequent sessions.
  4. Capture a handle-leak diagnostic if this repeats; it can indicate an SDK bug.
  5. Update the Aspire.Hosting.Browsers package.
Defensive patterns

Strategy: try-catch

Try / catch

try
{
    await StartTrackedBrowserAsync();
}
catch (Win32Exception ex) when (ex.Message.Contains("CloseHandle"))
{
    logger.LogWarning(ex, "Handle cleanup failed (Win32 {Code}); possible double-close.", ex.NativeErrorCode);
}

Prevention

When it happens

Trigger: CloseWindowsHandle(handle) is called by StartWindows with a valid (non-Zero) handle and CloseHandle returns FALSE - e.g. the handle was already closed elsewhere (double-close), or the handle value is invalid.

Common situations: An earlier failure path partially cleaned up handles then cleanup closes them again; another component closed the same handle value; handle table corruption; rare OS failures.

Related errors


AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16). Data as JSON: /api/errors/1c4d681371648c79. Report an issue: GitHub.

Appendix: source

Thrown at src/Aspire.Hosting.Browsers/BrowserLogsPipeBrowserProcessLauncher.Windows.cs:241

            }

            if (!GetExitCodeProcess(processHandle.DangerousGetHandle(), out var exitCode))
            {
                throw CreateWindowsException("GetExitCodeProcess");
            }

            return new BrowserLogsProcessResult(unchecked((int)exitCode));
        }).ConfigureAwait(false);
    }

    private static Win32Exception CreateWindowsException(string operation) =>
        new(Marshal.GetLastWin32Error(), $"Failed to invoke {operation} while starting tracked browser CDP pipe.");

    private static void CloseWindowsHandle(IntPtr handle)
    {
        if (handle != IntPtr.Zero && !CloseHandle(handle))
        {
            throw CreateWindowsException("CloseHandle");
        }
    }

    private static void TryKillProcessTree(int processId)
    {
        try
        {
            using var process = Process.GetProcessById(processId);
            if (!process.HasExited)
            {
                process.Kill(entireProcessTree: true);
            }
        }
        catch (ArgumentException)
        {
        }
        catch (InvalidOperationException)
        {

View on GitHub (pinned to 25830f84bd)