{"record":{"id":"b45797b053ba04b4","repo":"microsoft/aspire","slug":"failed-to-create-cli-kill-on-parent-exit-job-object","errorCode":null,"errorMessage":"Failed to create CLI kill-on-parent-exit job object","messagePattern":"Failed to create CLI kill-on-parent-exit job object","errorType":"exception","errorClass":"Win32Exception","httpStatus":null,"severity":"critical","filePath":"src/Aspire.Cli/Processes/WindowsConsoleProcessJob.cs","lineNumber":69,"sourceCode":"    private static readonly Lazy<WindowsConsoleProcessJob> s_shared = new(static () => new WindowsConsoleProcessJob());\n\n    private readonly SafeFileHandle _jobHandle;\n    private int _disposed;\n\n    /// <summary>\n    /// The process-wide job, created on first access. Callers that opt into parent-lifetime\n    /// cleanup use this instead of receiving a job instance, so they cannot forget to supply one.\n    /// Intentionally never disposed in production: the OS closes the handle at process exit,\n    /// which is exactly the crash-safety net we want.\n    /// </summary>\n    public static WindowsConsoleProcessJob Shared => s_shared.Value;\n\n    public WindowsConsoleProcessJob()\n    {\n        _jobHandle = WindowsProcessInterop.CreateJobObjectW(nint.Zero, null);\n        if (_jobHandle.IsInvalid)\n        {\n            throw new Win32Exception(Marshal.GetLastWin32Error(), \"Failed to create CLI kill-on-parent-exit job object\");\n        }\n\n        try\n        {\n            // BREAKAWAY_OK is required so DCP can fork itself with CREATE_BREAKAWAY_FROM_JOB\n            // and survive the CLI exiting; KILL_ON_JOB_CLOSE catches everything else.\n            var info = new WindowsProcessInterop.JOBOBJECT_EXTENDED_LIMIT_INFORMATION\n            {\n                BasicLimitInformation =\n                {\n                    LimitFlags = WindowsProcessInterop.JobObjectLimitKillOnJobClose\n                                 | WindowsProcessInterop.JobObjectLimitBreakawayOk,\n                },\n            };\n\n            var infoSize = Marshal.SizeOf<WindowsProcessInterop.JOBOBJECT_EXTENDED_LIMIT_INFORMATION>();\n            var infoPtr = Marshal.AllocHGlobal(infoSize);\n            try","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Cli/Processes/WindowsConsoleProcessJob.cs#L51-L87","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Check NativeErrorCode: ERROR_ACCESS_DENIED points at a security policy — whitelist the Aspire CLI with EDR/AppLocker or run outside the restricted sandbox.","Retry in a plain console session to determine whether a container/CI sandbox is blocking job objects.","Free system resources / reboot if the error suggests kernel memory or handle exhaustion.","Run the child without KillOnParentExit if the environment cannot support job objects, and manage child cleanup explicitly.","Update the Aspire CLI and report with the exact error code if the environment is otherwise healthy."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try\n{\n    var process = isolatedProcess.Start(startInfo with { KillOnParentExit = true });\n}\ncatch (Win32Exception ex) when (ex.Message == \"Failed to create CLI kill-on-parent-exit job object\")\n{\n    // Environment blocks job objects — run unrestricted or disable KillOnParentExit and manage cleanup manually\n}","preventionTips":["Run the CLI in environments that permit job objects (not AppLocker/EDR-restricted or exotic sandboxes).","Whitelist Aspire CLI/DCP executables with security software.","Avoid launching the CLI inside nested job-restricted wrappers when kill-on-parent-exit matters.","If unavoidable, fall back to KillOnParentExit=false plus explicit child cleanup in your tooling."],"tags":["windows","process","job-object","win32","cleanup"],"backgroundTag":"permission-denied","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}