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

  1. Check the Win32 error code in the message; handle leaks are the usual cause — restart the worker process to release handles.
  2. Verify the worker isn't leaking job objects (Win32JobHandle must be dropped/closed per job).
  3. Retry the job after resource pressure drops.
  4. 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

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


AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03). Data as JSON: /api/errors/2946899cee54f707. Report an issue: GitHub.