{"record":{"id":"8b2dd9d02681dcae","repo":"windmill-labs/windmill","slug":"createtoolhelp32snapshot-e","errorCode":null,"errorMessage":"CreateToolhelp32Snapshot: {e}","messagePattern":"CreateToolhelp32Snapshot: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/windmill-worker/src/common.rs","lineNumber":830,"sourceCode":"        self.inner.try_wait()\n    }\n}\n\n/// Resume all threads of a process created with CREATE_SUSPENDED. We create the child\n/// suspended so it can be assigned to its job object before running any code; otherwise\n/// a child that forks a helper at startup could create it before the assignment and\n/// leave it outside the job (escaping KILL_ON_JOB_CLOSE reaping / the memory cap).\n/// (Ported from process-wrap's resume_threads.)\n#[cfg(windows)]\nfn resume_process(pid: u32) -> Result<(), std::io::Error> {\n    use windows::Win32::System::Diagnostics::ToolHelp::{\n        CreateToolhelp32Snapshot, Thread32First, Thread32Next, TH32CS_SNAPTHREAD, THREADENTRY32,\n    };\n    use windows::Win32::System::Threading::{OpenThread, ResumeThread, THREAD_SUSPEND_RESUME};\n\n    unsafe {\n        let snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0).map_err(|e| {\n            std::io::Error::new(\n                std::io::ErrorKind::Other,\n                format!(\"CreateToolhelp32Snapshot: {e}\"),\n            )\n        })?;\n        let mut entry = THREADENTRY32 {\n            dwSize: std::mem::size_of::<THREADENTRY32>() as u32,\n            cntUsage: 0,\n            th32ThreadID: 0,\n            th32OwnerProcessID: 0,\n            tpBasePri: 0,\n            tpDeltaPri: 0,\n            dwFlags: 0,\n        };\n        let mut res = Thread32First(snapshot, &mut entry);\n        while res.is_ok() {\n            if entry.th32OwnerProcessID == pid {\n                if let Ok(thread) = OpenThread(THREAD_SUSPEND_RESUME, false, entry.th32ThreadID) {\n                    ResumeThread(thread);","sourceCodeStart":812,"sourceCodeEnd":848,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/backend/windmill-worker/src/common.rs#L812-L848","documentation":"On Windows, resume_process enumerates all threads via CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD) to find and ResumeThread the child's threads (the child was started suspended). If the Win32 snapshot call fails, the error is wrapped into an io::Error with this message. Snapshot failure typically means the toolhelp subsystem could not be accessed for the calling process.","triggerScenarios":"start_child_process on Windows spawning a suspended child, then resume_process calling CreateToolhelp32Snapshot and the API returning a Win32 error (e.g. ERROR_ACCESS_DENIED or out-of-memory for the snapshot).","commonSituations":"Hardened/restricted Windows environments (job containers, service accounts without sufficient privileges), resource exhaustion creating a system-wide thread snapshot, antivirus or policy blocking toolhelp APIs.","solutions":["Check the Win32 error code appended to the message (map Windows error codes, e.g. 5 = access denied) and fix the underlying permission.","Run the worker under an account with normal process/thread access rights; avoid running inside heavily restricted sandboxes.","Retry the job; transient snapshot allocation failures can clear under lower memory pressure.","Update Windows/the windows crate if a known toolhelp regression applies."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// No pre-call check possible for toolhelp snapshot availability; verify the process runs with standard user privileges on Windows before spawning suspended children.","typeGuard":null,"tryCatchPattern":"match resume_process(pid) {\n    Err(e) if e.to_string().contains(\"CreateToolhelp32Snapshot\") => {\n        log::warn!(\"thread snapshot failed, retrying once: {e}\");\n        std::thread::sleep(std::time::Duration::from_millis(50));\n        resume_process(pid)?;\n    }\n    other => other?,\n}","preventionTips":["Run the worker under a normal (non-restricted) Windows account","Avoid hardened sandbox/AV configurations that block toolhelp APIs","Monitor worker handle/memory pressure to avoid snapshot allocation failures"],"tags":["windows","win32","process","worker"],"backgroundTag":"win32-api-call-failed","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"}