{"record":{"id":"019dca6d5f09bcb8","repo":"abhigyanpatwari/GitNexus","slug":"sandbox-copy-paths-collide-at-current","errorCode":null,"errorMessage":"sandbox_copy paths collide at {current}","messagePattern":"sandbox_copy paths collide at (.+?)","errorType":"exception","errorClass":"SandboxError","httpStatus":null,"severity":"error","filePath":"eval/workflow_bench/task_assets.py","lineNumber":510,"sourceCode":"        self.budget.total_bytes += len(target_bytes)\n        self._record(\n            AssetManifestEntry(\n                path=relative,\n                kind=\"symlink\",\n                size=len(target_bytes),\n                sha256=hashlib.sha256(target_bytes).hexdigest(),\n                link_target=target,\n            )\n        )\n\n    def _ensure_parents(self, relative: PurePosixPath) -> None:\n        current = PurePosixPath()\n        for part in relative.parts:\n            current /= part\n            existing = self.entries.get(current)\n            if existing is not None:\n                if existing.kind != \"directory\":\n                    raise SandboxError(f\"sandbox_copy paths collide at {current}\")\n                continue\n            self._record(AssetManifestEntry(path=current, kind=\"directory\"))\n            (self.destination / Path(*current.parts)).mkdir(mode=0o700, exist_ok=True)\n\n    def _record(self, entry: AssetManifestEntry) -> None:\n        _validate_manifest_path(entry.path)\n        existing = self.entries.get(entry.path)\n        if existing is not None:\n            if existing != entry:\n                raise SandboxError(f\"sandbox_copy paths collide at {entry.path}\")\n            return\n        if self.budget.entries >= MAX_TASK_ASSET_ENTRIES:\n            raise SandboxError(\"sandbox_copy exceeds the entry limit\")\n        self.entries[entry.path] = entry\n        self.budget.entries += 1\n\n    def ensure_directory(self, relative: PurePosixPath) -> None:\n        \"\"\"Record and create one extra directory inside this snapshot.","sourceCodeStart":492,"sourceCodeEnd":528,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/d540b00184d71a896261ee02670da9a92d59d8f7/eval/workflow_bench/task_assets.py#L492-L528","documentation":"Raised by _SnapshotBuilder._ensure_parents while walking the parent components of a path being recorded: if an intermediate path component was already recorded in the manifest as a non-directory entry (a file or symlink), the tree is inconsistent because a file cannot have children. This catches manifest-shape conflicts where a declared file path collides with a directory prefix of another declared path.","triggerScenarios":"Two sandbox_copy or dependency declarations where one names a file at path P and another names something under P/ (e.g. declaring both `repo/foo` as a file and `repo/foo/bar`). Also possible if a directory was recorded as a file due to a race, though the path-collision semantics are the primary trigger.","commonSituations":"A task declares `sandbox_copy: [\"repo/build\"]` where `build` is a regular file in one arm and a directory in another. Overlapping declarations that slipped past the overlap check because one side is a file. A symlink in the dependency tree (allow_symlinks=True) recorded at a path that another entry tries to treat as a directory parent.","solutions":["Inspect the declared paths and confirm none is simultaneously a file and a directory prefix: review `sandbox_copy` and `sandbox_dependencies` source/target pairs.","Ensure the repo tree is consistent — `build` should not be a file in one checkout and a directory in another; align the checked-out revision.","Narrow declarations so file and directory paths do not shadow each other.","Re-run after `git clean -fdx` to remove stray files that shadow intended directories."],"exampleFix":"// before — inconsistent tree: 'config' is a file, but a dep needs 'config/x'\n{\"sandbox_copy\": [\"repo/config\"],\n \"sandbox_dependencies\": [{\"source\": \"overlay/config/x\", \"target\": \"config/x\"}]}\n\n// after — rename so paths don't collide\nmv repo/config repo/config.json\n{\"sandbox_copy\": [\"repo/config.json\"]}","handlingStrategy":"validation","validationCode":"from pathlib import Path, PurePosixPath\n\ndef validate_no_path_shadowing(declared_paths: list[PurePosixPath]) -> None:\n    \"\"\"Reject if any path is both a file and a directory-prefix of another.\"\"\"\n    s = sorted(set(declared_paths))\n    for i, a in enumerate(s):\n        for b in s[i+1:]:\n            if a == b or b in a.parents or a in b.parents:\n                raise ValueError(f\"paths collide (nest/duplicate): {a} and {b}\")\n\nvalidate_no_path_shadowing([PurePosixPath(p) for p in task[\"sandbox_copy\"]])","typeGuard":null,"tryCatchPattern":"from eval.workflow_bench.propposer_sandbox import SandboxError\n\ntry:\n    snapshot = cache.prepare(task, repo=repo, resolved_sha=sha)\nexcept SandboxError as exc:\n    if \"paths collide\" in str(exc):\n        # inspect declared paths for a file vs directory-prefix conflict\n        raise\n    raise","preventionTips":["Confirm each declared path's on-disk type is stable across arms (a path should not be a file in one checkout and a directory in another).","Avoid declaring a file and a child of that file's path together.","Run `git clean -fdx` to remove stray files that shadow intended directories."],"tags":["sandbox","manifest","validation","paths","collision"],"backgroundTag":null,"analyzedSha":"d540b00184d71a896261ee02670da9a92d59d8f7","analyzedAt":"2026-08-12T19:50:25.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}