abhigyanpatwari/GitNexus · error · SandboxError

sandbox_copy declarations overlap: {path} and {other}

Error message

sandbox_copy declarations overlap: {path} and {other}

What it means

Raised by _sandbox_copy_declarations during a pairwise comparison of all declared paths: if any two are equal, or one is an ancestor (parent) of the other, the declarations overlap and are rejected. Overlapping declarations would cause the snapshot builder to record the same bytes twice or contest directory ownership, so the harness requires a non-overlapping set. The check is O(n^2) but n is small for legitimate task declarations.

Source

Thrown at eval/workflow_bench/task_assets.py:557

def _sandbox_copy_declarations(
    task: Mapping[str, Any],
) -> tuple[tuple[str, ...], tuple[PurePosixPath, ...]]:
    raw_declarations = task.get("sandbox_copy", [])
    if not isinstance(raw_declarations, list) or not all(isinstance(item, str) and item for item in raw_declarations):
        raise SandboxError("sandbox_copy must be a list of nonblank repository-relative paths")
    declarations = tuple(raw_declarations)
    paths: list[PurePosixPath] = []
    for raw in declarations:
        relative = PurePosixPath(raw)
        if relative.is_absolute() or not relative.parts or ".." in relative.parts:
            raise SandboxError(f"sandbox_copy must be a repository-relative path: {raw!r}")
        _validate_manifest_path(relative)
        paths.append(relative)
    for index, path in enumerate(paths):
        for other in paths[index + 1 :]:
            if path == other or path in other.parents or other in path.parents:
                raise SandboxError(f"sandbox_copy declarations overlap: {path} and {other}")
    return declarations, tuple(paths)


def _sandbox_dependency_declarations(
    task: Mapping[str, Any],
) -> tuple[_DependencyDeclaration, ...]:
    raw_declarations = task.get("sandbox_dependencies", [])
    if not isinstance(raw_declarations, list):
        raise SandboxError("sandbox_dependencies must be a list")
    declarations: list[_DependencyDeclaration] = []
    for item in raw_declarations:
        if (
            not isinstance(item, Mapping)
            or set(item) != {"source", "target"}
            or not all(isinstance(item[field], str) and item[field] for field in ("source", "target"))
        ):
            raise SandboxError("sandbox_dependencies entries require only nonblank source and target")
        source = str(item["source"])

View on GitHub (pinned to d540b00184)

Solutions

  1. De-duplicate and de-nest the sandbox_copy list so no entry is an ancestor of another: prefer the broadest single root per area.
  2. If you need both a broad root and a specific file under it, declare only the broad root — the child is captured automatically.
  3. Sort and review declarations: `sorted(set(paths))` then check each pair.
  4. Validate with the provided overlap guard before calling prepare() (see validationCode).

Example fix

// before
{"sandbox_copy": ["src", "src/lib", "src", "tests"]}

// after — drop nested and duplicate
{"sandbox_copy": ["src", "tests"]}
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import PurePosixPath

def validate_no_copy_overlap(task: dict) -> None:
    paths = [PurePosixPath(p) for p in task.get("sandbox_copy", [])]
    for i, a in enumerate(paths):
        for b in paths[i+1:]:
            if a == b or a in b.parents or b in a.parents:
                raise ValueError(f"sandbox_copy declarations overlap: {a} and {b}")

validate_no_copy_overlap(task)

Type guard

from pathlib import PurePosixPath

def copy_set_is_disjoint(paths: list[str]) -> bool:
    ps = [PurePosixPath(p) for p in paths]
    for i, a in enumerate(ps):
        for b in ps[i+1:]:
            if a == b or a in b.parents or b in a.parents:
                return False
    return True

Try / catch

from eval.workflow_bench.propposer_sandbox import SandboxError

try:
    snapshot = cache.prepare(task, repo=repo, resolved_sha=sha)
except SandboxError as exc:
    if "declarations overlap" in str(exc):
        # drop nested or duplicate entries from sandbox_copy
        raise
    raise

Prevention

When it happens

Trigger: Declaring both `repo/src` and `repo/src/lib` (parent + child), declaring the same path twice (`repo/src` and `repo/src`), or declaring `repo/src` and `repo/src` under different string spellings that PurePosixPath normalizes equal. Also `a/b` and `a/b/c`.

Common situations: Incrementally adding paths to a task without checking the existing set. Copying declarations from another task and merging. Syntactic duplicates from templating (`./src` and `src` normalize equal, so duplicates are caught, but a human may not realize).

Related errors


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