abhigyanpatwari/GitNexus · error · SandboxError
sandbox_copy exceeds the total byte limit
Error message
sandbox_copy exceeds the total byte limit
What it means
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.
Source
Thrown at eval/workflow_bench/task_assets.py:425
os.close(child)
after = os.fstat(descriptor)
if _mutation_identity(before) != _mutation_identity(after):
raise SandboxError(f"sandbox_copy directory changed while snapshotting: {relative}")
return
if not stat.S_ISREG(before.st_mode):
raise SandboxError(f"sandbox_copy accepts only regular files and directories: {relative}")
self._copy_file(descriptor, relative, before)
def _record_directory(self, relative: PurePosixPath) -> None:
self._ensure_parents(relative.parent)
self._record(AssetManifestEntry(path=relative, kind="directory"))
destination = self.destination / Path(*relative.parts)
destination.mkdir(mode=0o700, exist_ok=True)
def _copy_file(self, descriptor: int, relative: PurePosixPath, before: os.stat_result) -> None:
self._ensure_parents(relative.parent)
if self.budget.total_bytes + before.st_size > MAX_TASK_ASSET_BYTES:
raise SandboxError("sandbox_copy exceeds the total byte limit")
destination = self.destination / Path(*relative.parts)
flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL | getattr(os, "O_CLOEXEC", 0)
output = os.open(destination, flags, 0o600)
digest = hashlib.sha256()
copied = 0
try:
while True:
chunk = _read_source_chunk(descriptor, COPY_CHUNK_BYTES)
if not chunk:
break
copied += len(chunk)
if self.budget.total_bytes + copied > MAX_TASK_ASSET_BYTES:
raise SandboxError("sandbox_copy exceeds the total byte limit")
digest.update(chunk)
_write_all(output, chunk)
captured_mode = stat.S_IMODE(before.st_mode) if self.preserve_modes else 0
frozen_mode = 0o400 | (0o100 if self.preserve_modes and captured_mode & 0o111 else 0)
os.fchmod(output, frozen_mode)View on GitHub (pinned to d540b00184)
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.
Example fix
// before
{"sandbox_copy": ["repo/.gitnexus/index", "repo/coverage-report", "repo/test-fixtures/large-dataset.bin"]}
// after — drop the dataset, keep it out of the snapshot
{"sandbox_copy": ["repo/.gitnexus/index"]} Defensive patterns
Strategy: validation
Validate before calling
from pathlib import Path
import os
MAX_BYTES = 2 * 1024 * 1024 * 1024
def total_declared_bytes(repo: Path, declarations: list[str]) -> int:
total = 0
for raw in declarations:
root = repo / raw
for current, _, files in os.walk(root, followlinks=False):
for name in files:
p = Path(current) / name
st = p.lstat()
if (st.st_mode & 0o170000) == 0o100000: # S_ISREG
total += st.st_size
if total > MAX_BYTES:
return total
return total
# run before prepare
total = total_declared_bytes(repo_path, task["sandbox_copy"])
if total > MAX_BYTES:
raise ValueError(f"sandbox_copy declares {total} bytes, limit is {MAX_BYTES}") 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 "exceeds the total byte limit" in str(exc):
# largest offenders:
# du -ah <declared> | sort -rh | head
raise
raise Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- sandbox_copy exceeds the entry limit
- candidate destination parent must be a real directory: {rela
- evidence source must be a regular non-symlink file: {path}
- results directory is unavailable: {root}: {exc}
- results directory must be a real non-symlink directory: {roo
AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12).
Data as JSON: /api/errors/d1e8a1fd92d3048e.
Report an issue: GitHub.