abhigyanpatwari/GitNexus · error · SandboxError
task asset filesystem cannot reflink the snapshot and the bu
Error message
task asset filesystem cannot reflink the snapshot and the buffered fallback limit would be exceeded
What it means
When _try_reflink returns False (reflink unsupported — ext4, 9p, tmpfs, or cross-device; errnos EXDEV/EINVAL/ENOTTY/EOPNOTSUPP/ENOSYS) AND the entry size exceeds the remaining buffered-fallback budget (capped at MAX_BUFFERED_FALLBACK_BYTES = 512 MiB cumulative across all entries in the snapshot), materialization is aborted to avoid an unbounded buffered copy. This is a configuration/environment error, not a security violation.
Source
Thrown at eval/workflow_bench/task_assets.py:827
raise SandboxError(f"task asset snapshot file changed: {entry.path}")
temporary = destination.with_name(f".{destination.name}.{uuid.uuid4().hex}.tmp")
source_descriptor = os.open(source, os.O_RDONLY | getattr(os, "O_CLOEXEC", 0) | getattr(os, "O_NOFOLLOW", 0))
destination_descriptor = os.open(
temporary,
os.O_WRONLY | os.O_CREAT | os.O_EXCL | getattr(os, "O_CLOEXEC", 0),
0o600,
)
fallback_bytes = 0
try:
opened = os.fstat(source_descriptor)
if _mutation_identity(opened) != _mutation_identity(metadata):
raise SandboxError(f"task asset snapshot file changed: {entry.path}")
if _try_reflink(source_descriptor, destination_descriptor):
if os.fstat(destination_descriptor).st_size != entry.size:
raise SandboxError(f"task asset reflink produced an invalid file: {entry.path}")
else:
if entry.size > fallback_budget:
raise SandboxError(
"task asset filesystem cannot reflink the snapshot and the buffered fallback limit would be exceeded"
)
os.ftruncate(destination_descriptor, 0)
os.lseek(source_descriptor, 0, os.SEEK_SET)
while True:
chunk = os.read(source_descriptor, COPY_CHUNK_BYTES)
if not chunk:
break
_write_all(destination_descriptor, chunk)
fallback_bytes += len(chunk)
if fallback_bytes != entry.size:
raise SandboxError(f"task asset snapshot file changed while materializing: {entry.path}")
if _mutation_identity(opened) != _mutation_identity(os.fstat(source_descriptor)):
raise SandboxError(f"task asset snapshot file changed while materializing: {entry.path}")
os.fchmod(destination_descriptor, 0o600)
finally:
os.close(destination_descriptor)
os.close(source_descriptor)View on GitHub (pinned to d540b00184)
Solutions
- Move the cache dir to a reflink-capable filesystem (btrfs or xfs) so the buffered fallback is not needed
- If a buffered copy is mandatory, shrink the offending asset below 512 MiB
- Avoid stacking many large assets in one snapshot — each reduces the remaining budget
Example fix
# before: cache on ext4 (no reflink) -> 428 MiB index hits the 512 MiB cap # export WFBENCH_TASK_ASSET_CACHE=/var/cache/wfbench # after: cache on btrfs so FICLONE reflink is used (no fallback budget consumed) # mkdir -p /mnt/btrfs/wfbench-cache # export WFBENCH_TASK_ASSET_CACHE=/mnt/btrfs/wfbench-cache
Defensive patterns
Strategy: validation
Validate before calling
import errno, fcntl, os, tempfile
from pathlib import Path
FICLONE = 0x40049409
MAX_BUFFERED_FALLBACK_BYTES = 512 * 1024 * 1024
def cache_supports_reflink(cache_dir: Path) -> bool:
a = cache_dir / ".reflink_probe_a"; b = cache_dir / ".reflink_probe_b"
try:
a.write_bytes(b"x"); b.touch()
fa = os.open(a, os.O_RDONLY); fb = os.open(b, os.O_WRONLY)
try:
fcntl.ioctl(fb, FICLONE, fa); return True
except OSError as exc:
return exc.errno not in {errno.EXDEV, errno.EINVAL, errno.ENOTTY, errno.EOPNOTSUPP, errno.ENOSYS}
finally:
os.close(fa); os.close(fb)
finally:
a.unlink(missing_ok=True); b.unlink(missing_ok=True)
def fits_fallback_budget(total_entry_bytes: int) -> bool:
return total_entry_bytes <= MAX_BUFFERED_FALLBACK_BYTES Try / catch
from eval.workflow_bench.proposer_sandbox import SandboxError
try:
snapshot.materialize(clone)
except SandboxError as exc:
if "cannot reflink" in str(exc):
raise SystemExit(f"move the cache to a reflink-capable fs (btrfs/xfs) or shrink the asset: {exc}") from exc
raise Prevention
- Place TaskAssetCache.root on a reflink-capable filesystem (btrfs or xfs) so FICLONE succeeds and the buffered fallback is never used
- Keep individual sandbox_copy assets below 512 MiB, and the cumulative total below the same cap, for non-reflink filesystems
- Probe reflink support on the cache dir at startup and fail fast if unsupported with oversized assets
When it happens
Trigger: Running on a filesystem without reflink support (ext4 CI runner, 9p-backed dev mount) with a sandbox_copy asset larger than 512 MiB; or cumulative assets draining the shared budget.
Common situations: CI on ext4 with a large GitNexus index (~428 MiB shipped, growing); Docker dev mount over 9p; the shipped index grew past the budget after a release.
Related errors
- task asset reflink produced an invalid file: {entry.path}
- ${TRUSTED_CACHE_DIRECTORY_ENV} must name a pre-existing prot
- 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}
AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12).
Data as JSON: /api/errors/20835630fdc23ccb.
Report an issue: GitHub.