windmill-labs/windmill · error
CreateJobObjectW: {e}
Error message
CreateJobObjectW: {e} What it means
assign_job_object creates a Windows Job object (CreateJobObjectW) to attach a child process so it can be killed and limited as a unit. If the kernel cannot create the job object, the error is wrapped with this message. Job object creation essentially only fails on resource/permission problems.
Source
Thrown at backend/windmill-worker/src/common.rs:874
Ok(())
}
/// Create a Windows Job Object and assign the process to it, optionally with
/// KILL_ON_JOB_CLOSE (so the child tree is reaped when the worker drops the handle /
/// dies) and/or a memory limit. Assigning post-spawn (rather than via process-wrap's
/// suspend/resume JobObject wrap) keeps the dotnet-safe behavior that csharp relies on.
#[cfg(windows)]
fn assign_job_object(
pid: u32,
memory_limit: Option<usize>,
kill_on_close: bool,
) -> Result<Win32JobHandle, std::io::Error> {
use windows::Win32::System::JobObjects::*;
use windows::Win32::System::Threading::{OpenProcess, PROCESS_SET_QUOTA, PROCESS_TERMINATE};
unsafe {
let job = CreateJobObjectW(None, None).map_err(|e| {
std::io::Error::new(std::io::ErrorKind::Other, format!("CreateJobObjectW: {e}"))
})?;
let mut info = JOBOBJECT_EXTENDED_LIMIT_INFORMATION::default();
if kill_on_close {
info.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
}
if let Some(memory_limit) = memory_limit {
info.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_JOB_MEMORY;
info.JobMemoryLimit = memory_limit;
}
SetInformationJobObject(
job,
JobObjectExtendedLimitInformation,
&info as *const _ as _,
std::mem::size_of::<JOBOBJECT_EXTENDED_LIMIT_INFORMATION>() as u32,
)
.map_err(|e| {View on GitHub (pinned to e474e8803c)
Solutions
- Check the Win32 error code in the message; handle leaks are the usual cause — restart the worker process to release handles.
- Verify the worker isn't leaking job objects (Win32JobHandle must be dropped/closed per job).
- Retry the job after resource pressure drops.
- Run in a normal user session rather than a stripped-down service context if policy blocks object creation.
Defensive patterns
Strategy: retry
Validate before calling
// Nothing callable to pre-validate; ensure the worker process has ample handle budget and is not near resource exhaustion before spawning children.
Try / catch
match assign_job_object(pid, true) {
Err(e) if e.to_string().contains("CreateJobObjectW") => {
// transient resource failure: surface to caller for job-level retry
Err(e)
}
other => other,
} Prevention
- Restart workers periodically to release leaked handles
- Ensure Win32JobHandle is always dropped so job objects close
- Watch Windows handle counts on long-running workers
When it happens
Trigger: start_child_process on Windows calling assign_job_object(pid, kill_on_close); CreateJobObjectW returns an error handle, e.g. when the system is out of handles/memory or object-name quota is exhausted.
Common situations: Resource exhaustion on a long-running Windows worker (handle leak), extremely restricted security contexts, or corrupted system state after many spawned jobs.
Related errors
- AssignProcessToJobObject: {e}
- CreateToolhelp32Snapshot: {e}
- SetInformationJobObject: {e}
- OpenProcess({pid}): {e}
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/2946899cee54f707.
Report an issue: GitHub.