abhigyanpatwari/GitNexus · error · OSError

NtResumeProcess failed

Error message

NtResumeProcess failed

What it means

After assigning the suspended child to the job, ntdll.NtResumeProcess is called to start it. If it returns a non-zero NTSTATUS, OSError(status, 'NtResumeProcess failed') is raised; the except block kills the still-suspended child and closes the job. This is rare and usually indicates the process already exited or the handle is invalid.

Source

Thrown at eval/workflow_bench/process_control.py:269

        ntdll.NtResumeProcess.restype = wintypes.LONG

        handle = kernel32.CreateJobObjectW(None, None)
        if not handle:
            raise OSError(ctypes.get_last_error(), "CreateJobObjectW failed")
        self._kernel32 = kernel32
        self._handle = handle
        ownership_slot[-1] = (process, self, None)
        try:
            limits = JOBOBJECT_EXTENDED_LIMIT_INFORMATION()
            limits.BasicLimitInformation.LimitFlags = 0x00002000  # KILL_ON_JOB_CLOSE
            if not kernel32.SetInformationJobObject(handle, 9, ctypes.byref(limits), ctypes.sizeof(limits)):
                raise OSError(ctypes.get_last_error(), "SetInformationJobObject failed")
            process_handle = wintypes.HANDLE(int(process._handle))  # type: ignore[attr-defined]
            if not kernel32.AssignProcessToJobObject(handle, process_handle):
                raise OSError(ctypes.get_last_error(), "AssignProcessToJobObject failed")
            status = int(ntdll.NtResumeProcess(process_handle))
            if status != 0:
                raise OSError(status, "NtResumeProcess failed")
        except BaseException:
            # The child is still suspended when assignment fails. Kill it
            # before releasing any handle; never retry with job breakaway.
            process.kill()
            process.wait()
            self.close()
            raise

    def terminate(self) -> None:
        import ctypes

        if self._handle and not self._kernel32.TerminateJobObject(self._handle, 1):
            raise OSError(ctypes.get_last_error(), "TerminateJobObject failed")

    def active_processes(self) -> int:
        """Return live members so closing the job cannot hide forced cleanup."""

        import ctypes

View on GitHub (pinned to d540b00184)

Solutions

  1. Decode the NTSTATUS: 0xC0000008 = invalid handle, 0xC000010A = process already terminating — both point at the child dying on launch.
  2. Run the same command directly in cmd.exe to confirm it starts at all (look for missing DLL / bad path).
  3. Disable AV real-time scanning briefly to see if it is killing the spawn.
  4. Run on Linux to avoid the NtResumeProcess path.
Defensive patterns

Strategy: try-catch

Validate before calling

# Validate the executable exists and is launchable before the owned spawn.
import shutil
if not shutil.which(cmd[0]):
    raise FileNotFoundError(f'{cmd[0]} not on PATH; NtResumeProcess would race a fast fail')

Try / catch

try:
    run_managed(cmd, timeout=60)
except OSError as exc:
    if sys.platform == 'win32' and 'NtResumeProcess' in str(exc):
        log.error('child died on launch; run %s directly to see why', cmd)
    raise

Prevention

When it happens

Trigger: On Windows when NtResumeProcess returns non-zero — STATUS_INVALID_HANDLE (0xC0000008), STATUS_PROCESS_IS_TERMINATING (0xC000010A), or similar. Usually a race where the child died between CreateProcess(CREATE_SUSPENDED) and the resume call.

Common situations: The child process crashed or was killed by AV immediately on load; the process_handle cast from process._handle lost precision; very fast-failing executables (missing DLL, bad path).

Related errors


AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12). Data as JSON: /api/errors/23f9a8d0672abf7b. Report an issue: GitHub.