{"record":{"id":"341d9be9a43bd669","repo":"microsoft/aspire","slug":"failed-to-add-job-object-to-process-thread-attribute-list","errorCode":null,"errorMessage":"Failed to add job object to process thread attribute list","messagePattern":"Failed to add job object to process thread attribute list","errorType":"exception","errorClass":"Win32Exception","httpStatus":null,"severity":"error","filePath":"src/Aspire.Cli/Processes/WindowsProcessInterop.cs","lineNumber":431,"sourceCode":"                        throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error(), \"Failed to update process thread attribute list\");\n                    }\n\n                    if (jobHandle is not null)\n                    {\n                        jobHandle.DangerousAddRef(ref jobHandleRefAdded);\n                        var jobHandles = new[] { jobHandle.DangerousGetHandle() };\n                        pinnedJobHandles = GCHandle.Alloc(jobHandles, GCHandleType.Pinned);\n\n                        if (!UpdateProcThreadAttribute(\n                            attrList,\n                            0,\n                            ProcThreadAttributeJobList,\n                            pinnedJobHandles.AddrOfPinnedObject(),\n                            (nint)(nint.Size * jobHandles.Length),\n                            nint.Zero,\n                            nint.Zero))\n                        {\n                            throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error(), \"Failed to add job object to process thread attribute list\");\n                        }\n                    }\n\n                    var si = new STARTUPINFOEX\n                    {\n                        cb = Marshal.SizeOf<STARTUPINFOEX>(),\n                        dwFlags = StartfUseStdHandles | StartfUseShowWindow,\n                        hStdInput = stdio.Stdin,\n                        hStdOutput = stdio.Stdout,\n                        hStdError = stdio.Stderr,\n                        lpAttributeList = attrList,\n                        // CREATE_NO_WINDOW is ignored with CREATE_NEW_CONSOLE; SW_HIDE keeps\n                        // the new console window off-screen.\n                        wShowWindow = ShowWindowHide,\n                    };\n\n                    var commandLine = BuildCommandLine(fileName, arguments);\n","sourceCodeStart":413,"sourceCodeEnd":449,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Cli/Processes/WindowsProcessInterop.cs#L413-L449","documentation":"The Aspire CLI attaches the kill-on-parent-exit Job Object to a spawned child via UpdateProcThreadAttribute with ProcThreadAttributeJobList so the child is assigned to the job at creation time. This error is thrown when that specific attribute update fails, wrapped with the last Win32 error. The child would then not be bound to the job, so CLI crash-cleanup cannot guarantee its termination.","triggerScenarios":"Starting a Windows child process with killOnParentExit enabled where UpdateProcThreadAttribute(ProcThreadAttributeJobList) returns false — commonly when the job handle is invalid, the job has JOB_OBJECT_LIMIT_BREAKAWAY_OK restrictions conflicting with the target, or the process is already inside an incompatible job.","commonSituations":"Running the CLI inside an outer job (CI runners, container runtimes, RDP session jobs) that does not permit nested job assignment; job handle SafeHandle was released before the call (DangerousAddRef race); EDR blocking job-list attributes.","solutions":["Read the inner Win32Exception code; ERROR_ACCESS_DENIED on the job handle points to outer-job nesting restrictions.","Run the CLI outside restrictive job environments (adjust CI runner configuration or use breakaway).","Retry the operation to rule out a transient SafeHandle lifetime race.","Update/report the issue to the Aspire CLI if reproducible outside sandboxed environments."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try\n{\n    await runner.StartAsync(exe, args, killOnParentExit: true);\n}\ncatch (Win32Exception ex)\n{\n    logger.LogWarning(\"Job-list attribute failed (Win32 error {Code}); child may outlive the CLI.\", ex.ErrorCode);\n}","preventionTips":["Do not nest the CLI inside foreign Job Objects with restrictive limits (CI runners).","Prefer running the CLI directly in a session rather than under job-wrapping supervisors.","Check EDR policies that block job-list process attributes."],"tags":["windows","win32","job-object","process-management","cli"],"backgroundTag":"win32-api-call-failed","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"}