abhigyanpatwari/GitNexus · error · OSError

QueryInformationJobObject failed

Error message

QueryInformationJobObject failed

What it means

active_processes() queries JobObjectBasicAccountingInformation via QueryInformationJobObject to count live children so the harness can prove ownership. If the handle is unset or the query returns FALSE, OSError(get_last_error(), ...) is raised — the harness refuses to claim ownership is healthy without proof.

Source

Thrown at eval/workflow_bench/process_control.py:311

                ("TotalKernelTime", ctypes.c_longlong),
                ("ThisPeriodTotalUserTime", ctypes.c_longlong),
                ("ThisPeriodTotalKernelTime", ctypes.c_longlong),
                ("TotalPageFaultCount", wintypes.DWORD),
                ("TotalProcesses", wintypes.DWORD),
                ("ActiveProcesses", wintypes.DWORD),
                ("TotalTerminatedProcesses", wintypes.DWORD),
            ]

        info = JOBOBJECT_BASIC_ACCOUNTING_INFORMATION()
        returned = wintypes.DWORD()
        if not self._handle or not self._kernel32.QueryInformationJobObject(
            self._handle,
            1,  # JobObjectBasicAccountingInformation
            ctypes.byref(info),
            ctypes.sizeof(info),
            ctypes.byref(returned),
        ):
            raise OSError(ctypes.get_last_error(), "QueryInformationJobObject failed")
        return int(info.ActiveProcesses)

    def close(self) -> None:
        if self._handle:
            self._kernel32.CloseHandle(self._handle)
            self._handle = None


def _spawn(
    command: Sequence[str] | str,
    *,
    cwd: Path | str | None,
    env: Mapping[str, str] | None,
    shell: bool,
    pipe_stdin: bool,
    ownership_slot: list[tuple[subprocess.Popen[bytes], _WindowsJob | None, int | None]],
) -> tuple[subprocess.Popen[bytes], _WindowsJob | None, str]:
    flags = 0

View on GitHub (pinned to d540b00184)

Solutions

  1. Do not call active_processes() after close() — track lifecycle in the caller.
  2. If OSError.errno is ERROR_INVALID_HANDLE (6) the job is closed; treat as 0 live processes at the caller.
  3. Verify the JOBOBJECT_BASIC_ACCOUNTING_INFORMATION size matches the running Windows version.
  4. Run on Linux where active_processes uses a process-group probe instead.
Defensive patterns

Strategy: validation

Validate before calling

# Only query active_processes while the job is open.
if job._handle is None:
    log.debug('job closed; reporting 0 active')
    return 0
return job.active_processes()

Try / catch

try:
    n = job.active_processes()
except OSError as exc:
    if sys.platform == 'win32' and exc.winerror == 6:  # ERROR_INVALID_HANDLE
        return 0
    raise

Prevention

When it happens

Trigger: Called during abort / shutdown bookkeeping on Windows when self._handle is None (already closed) or the query call fails. The OR short-circuit means a None handle alone triggers it.

Common situations: Calling active_processes() after close(); querying a job whose child was already reaped by the OS; struct size mismatch on older Windows.

Related errors


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