abhigyanpatwari/GitNexus · error · SandboxError
dependency snapshot changed: {dependency.source}
Error message
dependency snapshot changed: {dependency.source} What it means
In TaskAssetSnapshot.dependency_mounts, each dependency's captured source under the frozen snapshot root must still be the expected type (directory or regular file) and must not be a symlink. If lstat disagrees with what was captured, the snapshot was mutated and the mount is refused.
Source
Thrown at eval/workflow_bench/task_assets.py:170
finally:
shutil.rmtree(staging, ignore_errors=True)
def dependency_mounts(self, clone: Path) -> list[ReadOnlyMount]:
"""Mount only immutable captured dependency roots into an arm clone."""
clone = _real_directory(clone, label="dependency clone")
snapshot_root = _real_directory(self.root, label="task asset snapshot")
mounts: list[ReadOnlyMount] = []
for dependency in self.dependencies:
source = snapshot_root / Path(*dependency.snapshot_path.parts)
metadata = source.lstat()
expected_directory = dependency.kind == "directory"
if (
stat.S_ISLNK(metadata.st_mode)
or (expected_directory and not stat.S_ISDIR(metadata.st_mode))
or (not expected_directory and not stat.S_ISREG(metadata.st_mode))
):
raise SandboxError(f"dependency snapshot changed: {dependency.source}")
target = PurePosixPath(dependency.target)
_prepare_clone_target(
clone,
target,
directory=expected_directory,
label="dependency",
)
mounts.append(
ReadOnlyMount(
source=source,
target=f"{SANDBOX_WORKSPACE}/{target.as_posix()}",
)
)
return mounts
class TaskAssetCache:
"""Own immutable snapshots for one benchmark invocation."""View on GitHub (pinned to d540b00184)
Solutions
- Confirm _freeze_snapshot ran on the snapshot and the tree is mode 0500/0400.
- Ensure the cache root is single-writer and not shared across benchmark processes that could mutate it.
- Re-capture the snapshot (drop the cache entry) so it is freshly frozen.
Defensive patterns
Strategy: validation
Validate before calling
import os, stat
from pathlib import Path
def assert_dependency_snapshot_intact(snapshot_root, dependencies):
for dep in dependencies:
src = Path(snapshot_root, *dep.snapshot_path.parts)
m = src.lstat()
expected_dir = dep.kind == "directory"
if stat.S_ISLNK(m.st_mode):
raise RuntimeError(f"dependency snapshot became a symlink: {dep.source}")
if expected_dir and not stat.S_ISDIR(m.st_mode):
raise RuntimeError(f"dependency snapshot not a directory: {dep.source}")
if not expected_dir and not stat.S_ISREG(m.st_mode):
raise RuntimeError(f"dependency snapshot not a regular file: {dep.source}") Prevention
- Confirm _freeze_snapshot ran and the cache tree is mode 0500/0400.
- Keep the cache root exclusive to one TaskAssetCache; do not share across processes.
- Re-capture the snapshot if any dependency path is mutated.
When it happens
Trigger: Between snapshot capture and dependency_mounts (called per arm), the frozen snapshot's dependency path became a symlink or changed type - e.g. _freeze_snapshot did not actually lock it, or an external process mutated the nominally-immutable tree.
Common situations: A bug in freeze/thaw leaving the snapshot writable; concurrent arms racing on a shared cache root; external tampering with the cache directory.
Related errors
- {label} is unreadable: {path}: {exc}
- {label} changed while opening: {path}
- transcript artifact size does not match its results row: {pa
- transcript artifact changed while opening: {path}
- transcript artifact changed while reading: {path}
AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12).
Data as JSON: /api/errors/51b357f5e70b22b0.
Report an issue: GitHub.