abhigyanpatwari/GitNexus · error · ValueError

timeout and tail_bytes must be positive; terminate_grace mus

Error message

timeout and tail_bytes must be positive; terminate_grace must be non-negative

What it means

First validation block of _run_managed_inner: timeout must be > 0, terminate_grace must be >= 0, and tail_bytes must be > 0. These are caller-supplied numeric knobs; a violation is a programming error, not a runtime condition, and the function refuses to spawn anything.

Source

Thrown at eval/workflow_bench/process_control.py:428

def _run_managed_inner(
    command: Sequence[str] | str,
    *,
    cwd: Path | str | None = None,
    env: Mapping[str, str] | None = None,
    shell: bool = False,
    timeout: float,
    terminate_grace: float = DEFAULT_TERMINATE_GRACE,
    tail_bytes: int = MAX_TAIL_BYTES,
    require_pid_namespace: bool = False,
    stdin_data: bytes | None = None,
    capture_stdout_bytes: int | None = None,
    _ownership_slot: list[tuple[subprocess.Popen[bytes], _WindowsJob | None, int | None]],
) -> ManagedProcessResult:
    """Implementation registered with an outer post-spawn ownership guard."""

    started = time.monotonic()
    if timeout <= 0 or terminate_grace < 0 or tail_bytes <= 0:
        raise ValueError("timeout and tail_bytes must be positive; terminate_grace must be non-negative")
    if capture_stdout_bytes is not None and capture_stdout_bytes <= 0:
        raise ValueError("capture_stdout_bytes must be positive when supplied")
    if require_pid_namespace:
        if os.name == "nt":
            return _empty_result("ownership-failure", started, "PID-namespace execution is not supported on Windows")
        if not _pid_namespace_wrapper(command, shell):
            return _empty_result(
                "ownership-failure",
                started,
                "required Bubblewrap --unshare-pid/--die-with-parent ownership is absent",
            )

    try:
        process, job, ownership = _spawn(
            command,
            cwd=cwd,
            env=env,
            shell=shell,

View on GitHub (pinned to d540b00184)

Solutions

  1. Pass a positive timeout (e.g. 60) and a non-negative terminate_grace (default DEFAULT_TERMINATE_GRACE).
  2. If you need to disable tail capping, pass MAX_TAIL_BYTES explicitly, not 0.
  3. Validate numeric config at parse time so a missing key falls back to a sane default rather than 0.
  4. Add a unit test asserting the validators reject zero/negative values.

Example fix

// before
run_managed(['git','status'], timeout=0, tail_bytes=0)
// after
run_managed(['git','status'], timeout=60, tail_bytes=MAX_TAIL_BYTES)
Defensive patterns

Strategy: validation

Validate before calling

def validate_run_args(*, timeout: float, terminate_grace: float, tail_bytes: int) -> None:
    if timeout <= 0:
        raise ValueError('timeout must be > 0')
    if terminate_grace < 0:
        raise ValueError('terminate_grace must be >= 0')
    if tail_bytes <= 0:
        raise ValueError('tail_bytes must be > 0; use MAX_TAIL_BYTES to disable capping')

# call before run_managed(...)

Prevention

When it happens

Trigger: Calling run_managed / run_checked / _run_managed_inner with timeout=0 or negative, terminate_grace negative, or tail_bytes <= 0. Often a default-value bug or a config-driven value parsed as 0.

Common situations: Loading timeout from env/config that defaults to 0 when unset; passing `tail_bytes=0` thinking it disables capping (it doesn't — use MAX_TAIL_BYTES); passing terminate_grace=-1 hoping to skip grace.

Understand the failure class

Related errors


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