{"record":{"id":"95d9cc7870a62464","repo":"windmill-labs/windmill","slug":"assignprocesstojobobject-e","errorCode":null,"errorMessage":"AssignProcessToJobObject: {e}","messagePattern":"AssignProcessToJobObject: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/windmill-worker/src/common.rs","lineNumber":913,"sourceCode":"                std::io::ErrorKind::Other,\n                format!(\"SetInformationJobObject: {e}\"),\n            )\n        })?;\n\n        let process_handle = OpenProcess(PROCESS_SET_QUOTA | PROCESS_TERMINATE, false, pid)\n            .map_err(|e| {\n                let _ = windows::Win32::Foundation::CloseHandle(job);\n                std::io::Error::new(\n                    std::io::ErrorKind::Other,\n                    format!(\"OpenProcess({pid}): {e}\"),\n                )\n            })?;\n\n        let assign_result = AssignProcessToJobObject(job, process_handle);\n        let _ = windows::Win32::Foundation::CloseHandle(process_handle);\n        assign_result.map_err(|e| {\n            let _ = windows::Win32::Foundation::CloseHandle(job);\n            std::io::Error::new(\n                std::io::ErrorKind::Other,\n                format!(\"AssignProcessToJobObject: {e}\"),\n            )\n        })?;\n\n        Ok(Win32JobHandle(job))\n    }\n}\n\npub fn build_command_with_isolation(program: &str, args: &[&str]) -> Command {\n    use tokio::process::Command;\n\n    if crate::is_unshare_enabled() {\n        if let Some(unshare_path) = crate::UNSHARE_PATH.as_ref() {\n            let mut cmd = Command::new(unshare_path);\n\n            let flags = crate::UNSHARE_ISOLATION_FLAGS.as_str();\n            for flag in flags.split_whitespace() {","sourceCodeStart":895,"sourceCodeEnd":931,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/backend/windmill-worker/src/common.rs#L895-L931","documentation":"The final step of assign_job_object binds the opened child process handle to the job object via AssignProcessToJobObject. On failure the process and job handles are closed and this io::Error is returned. The classic cause is that the child is already part of another job that cannot host nested assignments (pre-Win8 semantics or explicitly configured).","triggerScenarios":"assign_job_object on Windows where the child already belongs to an incompatible job object — e.g. the worker itself runs inside a job (CI runner, service wrapper) on an OS/config that disallows nested job assignment, breaking the kill-on-close isolation for the job's child processes.","commonSituations":"Worker running under Windows service wrappers, CI agents, or job-based sandboxes (e.g. older Windows or strict job limit configuration) that forbid AssignProcessToJobObject on already-assigned processes.","solutions":["Check the Win32 error code: ERROR_ACCESS_DENIED typically means the process is already in another job.","Run the worker outside the parent job object (change how the service/CI wrapper launches it) or on Windows 8+ where nested jobs are supported.","Verify the job's limit flags don't include JOB_OBJECT_LIMIT_SILENT_BREAKAWAY restrictions incompatible with assignment.","Fallback: accept degraded cleanup (kill only the direct child pid) if nested jobs are impossible in your deployment."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Detect a likely parent job before spawning: workers inside CI/service job objects are prone to this failure.\n// Check whether the current process is already assigned to a job (QueryInformationJobObject on the enclosing job) when launching under such wrappers.","typeGuard":null,"tryCatchPattern":"match assign_job_object(pid, true) {\n    Err(e) if e.to_string().contains(\"AssignProcessToJobObject\") => {\n        log::warn!(\"nested job assignment denied: {e}; falling back to direct child kill\");\n        // degrade: kill only the direct child pid on cleanup\n        Ok(None)\n    }\n    other => other.map(Some),\n}","preventionTips":["Launch workers on Windows 8+ where nested job objects are supported","Avoid wrapping the worker in a second job object (strict CI/service sandboxes)","Allow breakaway or run the worker as a top-level process in deployments"],"tags":["windows","win32","job-object","process"],"backgroundTag":"assign-process-to-job-object-denied","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}