{"record":{"id":"d1e8a1fd92d3048e","repo":"abhigyanpatwari/GitNexus","slug":"sandbox-copy-exceeds-the-total-byte-limit","errorCode":null,"errorMessage":"sandbox_copy exceeds the total byte limit","messagePattern":"sandbox_copy exceeds the total byte limit","errorType":"exception","errorClass":"SandboxError","httpStatus":null,"severity":"error","filePath":"eval/workflow_bench/task_assets.py","lineNumber":425,"sourceCode":"                    os.close(child)\n            after = os.fstat(descriptor)\n            if _mutation_identity(before) != _mutation_identity(after):\n                raise SandboxError(f\"sandbox_copy directory changed while snapshotting: {relative}\")\n            return\n        if not stat.S_ISREG(before.st_mode):\n            raise SandboxError(f\"sandbox_copy accepts only regular files and directories: {relative}\")\n        self._copy_file(descriptor, relative, before)\n\n    def _record_directory(self, relative: PurePosixPath) -> None:\n        self._ensure_parents(relative.parent)\n        self._record(AssetManifestEntry(path=relative, kind=\"directory\"))\n        destination = self.destination / Path(*relative.parts)\n        destination.mkdir(mode=0o700, exist_ok=True)\n\n    def _copy_file(self, descriptor: int, relative: PurePosixPath, before: os.stat_result) -> None:\n        self._ensure_parents(relative.parent)\n        if self.budget.total_bytes + before.st_size > MAX_TASK_ASSET_BYTES:\n            raise SandboxError(\"sandbox_copy exceeds the total byte limit\")\n        destination = self.destination / Path(*relative.parts)\n        flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL | getattr(os, \"O_CLOEXEC\", 0)\n        output = os.open(destination, flags, 0o600)\n        digest = hashlib.sha256()\n        copied = 0\n        try:\n            while True:\n                chunk = _read_source_chunk(descriptor, COPY_CHUNK_BYTES)\n                if not chunk:\n                    break\n                copied += len(chunk)\n                if self.budget.total_bytes + copied > MAX_TASK_ASSET_BYTES:\n                    raise SandboxError(\"sandbox_copy exceeds the total byte limit\")\n                digest.update(chunk)\n                _write_all(output, chunk)\n            captured_mode = stat.S_IMODE(before.st_mode) if self.preserve_modes else 0\n            frozen_mode = 0o400 | (0o100 if self.preserve_modes and captured_mode & 0o111 else 0)\n            os.fchmod(output, frozen_mode)","sourceCodeStart":407,"sourceCodeEnd":443,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/d540b00184d71a896261ee02670da9a92d59d8f7/eval/workflow_bench/task_assets.py#L407-L443","documentation":"Raised by _SnapshotBuilder._copy_file as a pre-flight check before streaming any bytes: if the shared budget's total_bytes plus the file's reported st_size would exceed MAX_TASK_ASSET_BYTES (2 GiB), snapshotting aborts before opening the output. This is the early, size-based rejection — it uses the filesystem's reported size, not bytes actually read. It exists so a grossly oversized declaration fails fast rather than after a partial multi-hundred-megabyte copy.","triggerScenarios":"A single declared file whose st_size, added to the running budget, crosses 2*1024*1024*1024 bytes. Common when the shipped GitNexus index (~428 MiB) is declared alongside other large inputs, or when a task accidentally declares a huge generated artifact (coverage dump, core file, packed dataset) as sandbox_copy.","commonSituations":"Declaring `node_modules` plus a large index plus a coverage tarball in one task. Pointing sandbox_copy at a repo root that contains a multi-gigabyte `.git/objects/pack` or a vendored dataset. Misconfigured task that copies an entire build output tree rather than a slice.","solutions":["Reduce the declared sandbox_copy set so total bytes stay well under 2 GiB; the realistic ceiling is the ~428 MiB index plus modest extras.","Identify the largest files with `du -ah <declared-root> | sort -rh | head` and exclude generated/vendored blobs.","Split the task so the heaviest asset is mounted as a sandbox_dependency (read-only bind) rather than copied into the snapshot, if applicable.","If the large file is generated, add it to .gitignore and regenerate it inside the arm clone rather than capturing it."],"exampleFix":"// before\n{\"sandbox_copy\": [\"repo/.gitnexus/index\", \"repo/coverage-report\", \"repo/test-fixtures/large-dataset.bin\"]}\n\n// after — drop the dataset, keep it out of the snapshot\n{\"sandbox_copy\": [\"repo/.gitnexus/index\"]}","handlingStrategy":"validation","validationCode":"from pathlib import Path\nimport os\n\nMAX_BYTES = 2 * 1024 * 1024 * 1024\n\ndef total_declared_bytes(repo: Path, declarations: list[str]) -> int:\n    total = 0\n    for raw in declarations:\n        root = repo / raw\n        for current, _, files in os.walk(root, followlinks=False):\n            for name in files:\n                p = Path(current) / name\n                st = p.lstat()\n                if (st.st_mode & 0o170000) == 0o100000:  # S_ISREG\n                    total += st.st_size\n                    if total > MAX_BYTES:\n                        return total\n    return total\n\n# run before prepare\ntotal = total_declared_bytes(repo_path, task[\"sandbox_copy\"])\nif total > MAX_BYTES:\n    raise ValueError(f\"sandbox_copy declares {total} bytes, limit is {MAX_BYTES}\")","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 \"exceeds the total byte limit\" in str(exc):\n        # largest offenders:\n        #   du -ah <declared> | sort -rh | head\n        raise\n    raise","preventionTips":["Pre-compute declared bytes with `du -sb <each declared path>` and keep the sum well under 2 GiB.","Treat the ~428 MiB shipped index as the dominant asset; budget remaining space conservatively.","Prefer read-only sandbox_dependencies for large vendored trees over copying them into the snapshot."],"tags":["sandbox","limits","budget","filesystem"],"backgroundTag":null,"analyzedSha":"d540b00184d71a896261ee02670da9a92d59d8f7","analyzedAt":"2026-08-12T19:50:25.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}