abhigyanpatwari/GitNexus · error · SandboxError

{label} does not exist: {relative}

Error message

{label} does not exist: {relative}

What it means

Raised by _safe_repo_source, the trust-boundary validator for any task-declared repo-relative asset source. After confirming the path is repo-relative and cannot escape the repository root, it requires the resolved path to actually exist on disk; a missing file or directory is rejected because the subsequent read-only bubblewrap mount would silently fail or, worse, be redirected. This runs before containment starts, so the harness refuses to stage a non-existent asset rather than weaken the contract.

Source

Thrown at eval/workflow_bench/proposer_sandbox.py:572

    except OSError as exc:
        raise SandboxError(f"{label} must be a real directory: {lexical}: {exc}") from exc
    if resolved != lexical:
        raise SandboxError(f"{label} must not traverse symlinks: {lexical}")
    return lexical


def _safe_repo_source(repo: Path, relative: str, *, label: str) -> tuple[Path, Path]:
    candidate = PurePosixPath(relative)
    if candidate.is_absolute() or ".." in candidate.parts or not candidate.parts:
        raise SandboxError(f"{label} must be a repository-relative path: {relative!r}")
    lexical = repo / Path(*candidate.parts)
    resolved = lexical.resolve()
    try:
        resolved.relative_to(repo)
    except ValueError as exc:
        raise SandboxError(f"{label} escapes its allowed repository root: {relative}") from exc
    if not resolved.exists():
        raise SandboxError(f"{label} does not exist: {relative}")
    return lexical, resolved


def _prepare_clone_target(
    clone: Path,
    relative: PurePosixPath,
    *,
    directory: bool | None,
    label: str,
) -> Path:
    """Validate/create a clone-local target without following any symlink.

    This runs before Bubblewrap, so ordinary ``Path.mkdir``/``touch`` calls
    are not acceptable: an untrusted tracked parent symlink could redirect a
    mount placeholder write into the host filesystem.
    """

    flags = os.O_RDONLY | os.O_DIRECTORY | getattr(os, "O_CLOEXEC", 0)

View on GitHub (pinned to d540b00184)

Solutions

  1. Copy the exact relative path from the error and run `ls -la <repo>/<relative>` against the repo root the harness uses (the worktree at the task SHA, not your working copy).
  2. Confirm the asset is committed at that relative path in the resolved SHA: `git -C <repo> cat-file -e <sha>:<relative>`.
  3. If the path is wrong, fix the source/asset entry in the task YAML to the correct repository-relative path.
  4. If the asset is produced dynamically, ensure the producing step runs before staging and writes into the same worktree the harness will bind.

Example fix

// task YAML (before)
assets:
  - source: eval/workflow_bench/fixtures/NodeModules.json
// after — corrected relative path that exists in the repo
assets:
  - source: eval/workflow_bench/fixtures/node_modules.json
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path, PurePosixPath

def assert_repo_source_exists(repo: Path, relative: str) -> None:
    cand = PurePosixPath(relative)
    assert not cand.is_absolute() and '..' not in cand.parts and cand.parts, relative
    resolved = (repo / Path(*cand.parts)).resolve()
    resolved.relative_to(repo)  # raises ValueError if it escapes
    assert resolved.exists(), f'{relative} does not exist under {repo}'

Try / catch

from .proposer_sandbox import SandboxError

try:
    lexical, resolved = _safe_repo_source(repo, relative, label='asset')
except SandboxError as exc:
    # surface to the task author; do not proceed to staging
    raise

Prevention

When it happens

Trigger: A task YAML entry declares a dependency/asset source path (e.g. a node_modules snapshot, a fixture, or a config file) whose relative path does not exist under the resolved repo root at the task's checked-out SHA. Concretely: stage_task_assets -> _safe_repo_source(repo, relative, label=...) where Path(repo / relative).resolve().exists() is False.

Common situations: Path typo or wrong casing in the task file (especially macOS dev authoring vs. case-sensitive Linux CI); asset was renamed/moved after the task was authored; harness invoked from a different CWD or with a different --repo so 'repo' resolves elsewhere; asset exists only on a branch that is not checked out; the asset is generated by a setup step that ran in a different worktree.

Related errors


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