microsoft/aspire · critical · Win32Exception

Failed to create CLI kill-on-parent-exit job object

Error message

Failed to create CLI kill-on-parent-exit job object

What it means

WindowsConsoleProcessJob implements kill-on-parent-exit by creating a Windows Job Object (CreateJobObjectW) that will terminate assigned children when closed. If the job object cannot be created — an extremely rare kernel-level failure — the constructor throws this Win32Exception with the raw Win32 error and the CLI cannot provide parent-exit protection for console children.

Solutions

  1. Check NativeErrorCode: ERROR_ACCESS_DENIED points at a security policy — whitelist the Aspire CLI with EDR/AppLocker or run outside the restricted sandbox.
  2. Retry in a plain console session to determine whether a container/CI sandbox is blocking job objects.
  3. Free system resources / reboot if the error suggests kernel memory or handle exhaustion.
  4. Run the child without KillOnParentExit if the environment cannot support job objects, and manage child cleanup explicitly.
  5. Update the Aspire CLI and report with the exact error code if the environment is otherwise healthy.
Defensive patterns

Strategy: try-catch

Try / catch

try
{
    var process = isolatedProcess.Start(startInfo with { KillOnParentExit = true });
}
catch (Win32Exception ex) when (ex.Message == "Failed to create CLI kill-on-parent-exit job object")
{
    // Environment blocks job objects — run unrestricted or disable KillOnParentExit and manage cleanup manually
}

Prevention

When it happens

Trigger: Constructing WindowsConsoleProcessJob (lazily via WindowsConsoleProcessJob.Shared on first KillOnParentExit spawn) when WindowsProcessInterop.CreateJobObjectW(nint.Zero, null) returns an invalid handle; GetLastWin32Error supplies the code (commonly ERROR_ACCESS_DENIED or out-of-memory/kernel-resource exhaustion).

Common situations: Running in a heavily restricted sandbox, container, or security product that blocks job-object creation; kernel handle/memory exhaustion; nested job limits in exotic hosting environments.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


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

Appendix: source

Thrown at src/Aspire.Cli/Processes/WindowsConsoleProcessJob.cs:69

    private static readonly Lazy<WindowsConsoleProcessJob> s_shared = new(static () => new WindowsConsoleProcessJob());

    private readonly SafeFileHandle _jobHandle;
    private int _disposed;

    /// <summary>
    /// The process-wide job, created on first access. Callers that opt into parent-lifetime
    /// cleanup use this instead of receiving a job instance, so they cannot forget to supply one.
    /// Intentionally never disposed in production: the OS closes the handle at process exit,
    /// which is exactly the crash-safety net we want.
    /// </summary>
    public static WindowsConsoleProcessJob Shared => s_shared.Value;

    public WindowsConsoleProcessJob()
    {
        _jobHandle = WindowsProcessInterop.CreateJobObjectW(nint.Zero, null);
        if (_jobHandle.IsInvalid)
        {
            throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to create CLI kill-on-parent-exit job object");
        }

        try
        {
            // BREAKAWAY_OK is required so DCP can fork itself with CREATE_BREAKAWAY_FROM_JOB
            // and survive the CLI exiting; KILL_ON_JOB_CLOSE catches everything else.
            var info = new WindowsProcessInterop.JOBOBJECT_EXTENDED_LIMIT_INFORMATION
            {
                BasicLimitInformation =
                {
                    LimitFlags = WindowsProcessInterop.JobObjectLimitKillOnJobClose
                                 | WindowsProcessInterop.JobObjectLimitBreakawayOk,
                },
            };

            var infoSize = Marshal.SizeOf<WindowsProcessInterop.JOBOBJECT_EXTENDED_LIMIT_INFORMATION>();
            var infoPtr = Marshal.AllocHGlobal(infoSize);
            try

View on GitHub (pinned to 25830f84bd)