abhigyanpatwari/GitNexus · error · SandboxError

required executable is unavailable: {default}

Error message

required executable is unavailable: {default}

What it means

Raised by _resolve_executable when no executable was supplied and shutil.which(default) returned None — i.e. the required tool is not on PATH. The sandbox resolves tools like bwrap, socat, python3, node by name and refuses to proceed if the binary cannot be located, since containment correctness depends on the real binary being present.

Source

Thrown at eval/workflow_bench/proposer_sandbox.py:467

    /usr/bin/python3 is a real system binary, but it's root-owned on the host.
    Inside this --unshare-user sandbox only the calling uid is mapped (root is
    not), so root-owned files surface as the kernel's overflow uid — which
    evidence-provenance.mjs's PATH-scan correctly refuses to trust. This
    wrapper is freshly created by the same host process that owns
    home/temp/shell-prefix, so it maps to the sandbox's own trusted uid
    instead, and simply execs the real interpreter through to do the work.
    """

    wrapper = private_root / "python3"
    wrapper.write_text('#!/bin/bash\nset -eu\nexec /usr/bin/python3 "$@"\n')
    wrapper.chmod(0o500)
    return wrapper


def _resolve_executable(executable: Path | str | None, default: str) -> Path:
    raw = os.fspath(executable) if executable is not None else shutil.which(default)
    if not raw:
        raise SandboxError(f"required executable is unavailable: {default}")
    path = Path(raw).expanduser().resolve()
    if not path.is_file() or not os.access(path, os.X_OK):
        raise SandboxError(f"required executable is not an executable regular file: {path}")
    return path


def preflight_bubblewrap(bwrap_bin: Path | str | None = None) -> Path:
    """Prove the required namespaces work; never fall back to host execution."""

    if sys.platform != "linux":
        raise SandboxError(f"Bubblewrap containment is supported only on Linux/WSL2, not {sys.platform}")
    bwrap = _resolve_executable(bwrap_bin, "bwrap")
    command = [
        str(bwrap),
        "--unshare-user",
        "--unshare-pid",
        "--unshare-ipc",
        "--unshare-uts",

View on GitHub (pinned to d540b00184)

Solutions

  1. Install the missing tool: 'sudo apt-get install -y bubblewrap socat' (or distro equivalent).
  2. Verify with 'which bwrap socat' from the same shell/env the driver uses.
  3. If the tool lives at a known absolute path, pass it explicitly: preflight_bubblewrap('/usr/local/bin/bwrap').
  4. Fix PATH in the runner's environment so the directory containing the tool is present.

Example fix

// before
bwrap = preflight_bubblewrap()  # bwrap not on PATH
// after
# install first, then:
bwrap = preflight_bubblewrap('/usr/bin/bwrap')
Defensive patterns

Strategy: validation

Validate before calling

import shutil

def available(default: str) -> bool:
    return shutil.which(default) is not None

missing = [d for d in ('bwrap','socat','node','python3') if not available(d)]
if missing:
    raise EnvironmentError(f'install required tools: {missing}')

Type guard

import shutil

def is_resolvable_executable(default: str) -> bool:
    return shutil.which(default) is not None

Try / catch

try:
    bwrap = preflight_bubblewrap()
except SandboxError as exc:
    if 'unavailable' in str(exc):
        raise SystemExit(f'install bwrap: {exc}')
    raise

Prevention

When it happens

Trigger: _resolve_executable(None, 'bwrap') (or 'socat', 'node', etc.) where the named binary is absent from every directory in PATH. Also when an explicit executable value resolves to an empty string.

Common situations: bubblewrap not installed on the host (apt/dnf package missing); socat not installed (needed by the inner sandbox preflight); PATH is minimal inside CI/containers and omits /usr/bin or /usr/local/bin; running on a machine where the tool is aliased but not actually installed; a venv/uv activation rewrote PATH and dropped a directory.

Related errors


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