microsoft/aspire · error · Win32Exception

Failed to invoke GetExitCodeProcess while starting tracked…

Error message

Failed to invoke GetExitCodeProcess while starting tracked browser CDP pipe.

What it means

After the tracked browser process exits, the launcher reads its exit code via GetExitCodeProcess. If that OS call fails, this Win32Exception-named error is thrown. It means the exit status of the browser process could not be retrieved, so the CDP pipe session result is unknown.

Solutions

  1. Check the inner NativeErrorCode for the OS reason (typically ERROR_INVALID_HANDLE=6).
  2. Avoid closing/disposing the process handle while the launcher session is active.
  3. Retry the browser launch; the session result is unrecoverable.
  4. Verify the hosting account has rights to query process information.
  5. Update Aspire.Hosting.Browsers for potential handle-lifecycle fixes.
Defensive patterns

Strategy: retry

Validate before calling

if (processHandle.IsClosed || processHandle.IsInvalid)
    throw new InvalidOperationException("Browser process handle is no longer valid; exit code unavailable.");

Try / catch

try
{
    var result = await WaitForBrowserAsync(processHandle);
}
catch (Win32Exception ex) when (ex.Message.Contains("GetExitCodeProcess"))
{
    logger.LogWarning(ex, "Could not read browser exit code (Win32 {Code}); relaunching.", ex.NativeErrorCode);
    await RelaunchTrackedBrowserAsync();
}

Prevention

When it happens

Trigger: WaitForWindowsProcessAsync calls GetExitCodeProcess(processHandle.DangerousGetHandle(), out exitCode) and it returns FALSE - the handle is no longer valid or the OS call fails for handle/access reasons.

Common situations: Handle closed between the successful wait and the exit-code read; process cleanup racing with the launcher; restricted token lacking PROCESS_QUERY_INFORMATION; corrupted handle from an earlier failure.

Related errors


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

Appendix: source

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

            builder.Append(character);
        }

        builder.Append('"');
    }

    private static async Task<BrowserLogsProcessResult> WaitForWindowsProcessAsync(SafeWaitHandle processHandle)
    {
        return await Task.Run(() =>
        {
            var waitResult = WaitForSingleObject(processHandle.DangerousGetHandle(), INFINITE);
            if (waitResult != WAIT_OBJECT_0)
            {
                throw CreateWindowsException("WaitForSingleObject");
            }

            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)

View on GitHub (pinned to 25830f84bd)