abhigyanpatwari/GitNexus · error · SandboxError

sandbox_copy paths collide at {entry.path}

Error message

sandbox_copy paths collide at {entry.path}

What it means

Raised by _SnapshotBuilder._record when a manifest entry at a given path was already recorded with different fields (different kind, size, sha256, mode, or link_target). The second recording is rejected because the manifest must be deterministic — the same path cannot have two distinct captured identities in one snapshot. Identical re-recording is a no-op (the early `existing != entry` check returns).

Source

Thrown at eval/workflow_bench/task_assets.py:520

    def _ensure_parents(self, relative: PurePosixPath) -> None:
        current = PurePosixPath()
        for part in relative.parts:
            current /= part
            existing = self.entries.get(current)
            if existing is not None:
                if existing.kind != "directory":
                    raise SandboxError(f"sandbox_copy paths collide at {current}")
                continue
            self._record(AssetManifestEntry(path=current, kind="directory"))
            (self.destination / Path(*current.parts)).mkdir(mode=0o700, exist_ok=True)

    def _record(self, entry: AssetManifestEntry) -> None:
        _validate_manifest_path(entry.path)
        existing = self.entries.get(entry.path)
        if existing is not None:
            if existing != entry:
                raise SandboxError(f"sandbox_copy paths collide at {entry.path}")
            return
        if self.budget.entries >= MAX_TASK_ASSET_ENTRIES:
            raise SandboxError("sandbox_copy exceeds the entry limit")
        self.entries[entry.path] = entry
        self.budget.entries += 1

    def ensure_directory(self, relative: PurePosixPath) -> None:
        """Record and create one extra directory inside this snapshot.

        Used for harness-owned mount points that must exist in the captured
        bytes rather than be created against a read-only bind at runtime.
        """

        self._record_directory(relative)

    def finished_entries(self) -> tuple[AssetManifestEntry, ...]:
        return tuple(sorted(self.entries.values(), key=lambda entry: entry.path.as_posix()))

View on GitHub (pinned to d540b00184)

Solutions

  1. Review all sandbox_copy and sandbox_dependencies entries for paths that resolve to the same in-snapshot location; eliminate aliases.
  2. Quiesce the source tree so a file visited twice yields identical sha256 (stop concurrent writers).
  3. Ensure each dependency's source maps to a distinct snapshot_path (the harness uses indexed containers, so collision implies duplicate target declarations).
  4. Run detect_changes or a tree diff to confirm the source is stable across the capture window.

Example fix

// before — two deps target the same in-clone path with different sources
{"sandbox_dependencies": [
  {"source": "a/node_modules", "target": "node_modules"},
  {"source": "b/node_modules", "target": "node_modules"}
]}

// after — distinct targets
{"sandbox_dependencies": [
  {"source": "a/node_modules", "target": "node_modules"}
]}
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import PurePosixPath

def validate_distinct_in_snapshot_paths(copy_paths: list[PurePosixPath], dep_targets: list[PurePosixPath]) -> None:
    """Ensure no copy path aliases a dependency target and all targets are distinct."""
    seen = {}
    for p in list(copy_paths) + list(dep_targets):
        if p in seen:
            raise ValueError(f"duplicate in-snapshot path: {p}")
        seen[p] = True

validate_distinct_in_snapshot_paths(
    [PurePosixPath(p) for p in task["sandbox_copy"]],
    [PurePosixPath(d["target"]) for d in task.get("sandbox_dependencies", [])],
)

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 "paths collide" in str(exc):
        # two declarations resolve to the same in-snapshot path with different content
        raise
    raise

Prevention

When it happens

Trigger: The same relative path is captured twice with differing metadata within one prepare() call. This can happen if a file is mutated between two traversals (so its sha256 differs), or if the path is reached via two different declaration roots whose trees overlap in a way the declaration-overlap check did not block (e.g. a dependency payload path colliding with a sandbox_copy path).

Common situations: Two sandbox_dependency sources that both contain a `payload/foo` resolved to the same snapshot path but with different contents. A concurrent mutation that changes a file's sha256 between the first and second time the builder visits it. A misconfigured declaration where sandbox_copy and a dependency target alias the same in-snapshot path.

Related errors


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