abhigyanpatwari/GitNexus · error · SandboxError
sandbox dependency content changed after task binding
Error message
sandbox dependency content changed after task binding
What it means
Raised by _validate_dependency_binding_values when the sandbox_dependency_content_digest / sandbox_dependency_manifest_digest read from a task binding do not equal the freshly computed digests of the current dependency snapshot. Bindings pin the exact dependency bytes; any mismatch means dependency content drifted after the binding was captured, so running the arm would use different inputs than were recorded.
Source
Thrown at eval/workflow_bench/task_assets.py:961
manifest_digest = hashlib.sha256(
json.dumps(manifest_payload, sort_keys=True, separators=(",", ":")).encode()
).hexdigest()
return content_digest, manifest_digest
def _validate_dependency_binding_values(
binding: Mapping[str, Any],
*,
content_digest: str,
manifest_digest: str,
) -> None:
expected = {
DEPENDENCY_CONTENT_BINDING_FIELD: content_digest,
DEPENDENCY_MANIFEST_BINDING_FIELD: manifest_digest,
}
supplied = {field: binding.get(field) for field in expected}
if supplied != expected:
raise SandboxError("sandbox dependency content changed after task binding")
def _snapshot_digest(
*,
repo_identity: Path,
resolved_sha: str,
declarations: tuple[str, ...],
manifest_digest: str,
dependency_content_digest: str,
dependency_manifest_digest: str,
) -> str:
payload = {
"declarations": declarations,
"dependency_content_digest": dependency_content_digest,
"dependency_manifest_digest": dependency_manifest_digest,
"manifest_digest": manifest_digest,
"repo_identity": str(repo_identity),
"resolved_sha": resolved_sha,View on GitHub (pinned to d540b00184)
Solutions
- Re-capture the binding immediately before staging assets: call capture_task_dependency_binding(task, repo=repo, resolved_sha=sha) and store its result, then pass the same dict to validate_dependency_binding.
- Ensure the dependency source tree is read-only / at a fixed resolved_sha between capture and validation (checkout the pinned sha in both steps).
- If you serialized the binding, verify the keys sandbox_dependency_content_digest and sandbox_dependency_manifest_digest round-trip unchanged (no float coercion, no truncation).
Example fix
# before: binding captured once, repo later moved
binding = capture_task_dependency_binding(task, repo=repo, resolved_sha=old_sha)
git_checkout('main') # dependency bytes changed
snapshot.validate_dependency_binding(binding) # -> mismatch
# after: capture and validate at the same sha
snapshot = cache.prepare(task, repo=repo, resolved_sha=sha)
binding = snapshot.dependency_binding
# ... no repo mutation in between ...
snapshot.validate_dependency_binding(binding) Defensive patterns
Strategy: validation
Validate before calling
from .task_assets import capture_task_dependency_binding, TaskAssetCache
def fresh_binding(task, *, repo, resolved_sha) -> dict[str, str]:
# Always (re)capture at the exact sha you will run against.
return capture_task_dependency_binding(task, repo=repo, resolved_sha=resolved_sha)
# Compare against any stored binding *before* staging:
expected = snapshot.dependency_binding
if stored != expected:
raise ValueError('stored dependency binding is stale; recapture before staging') Type guard
def binding_matches(binding: Mapping[str, object], snapshot: 'TaskAssetSnapshot') -> bool:
return binding == snapshot.dependency_binding Try / catch
from .proposer_sandbox import SandboxError
try:
snapshot.validate_dependency_binding(binding)
except SandboxError as exc:
if 'dependency content changed' in str(exc):
# Re-capture at the current sha and update the stored binding; do NOT
# edit the binding by hand.
binding = capture_task_dependency_binding(task, repo=repo, resolved_sha=sha)
snapshot.validate_dependency_binding(binding)
else:
raise Prevention
- Capture the dependency binding in the same checkout/commit you stage against.
- Treat the binding as opaque: never hand-edit the digest keys.
- If you serialize bindings, verify the digest keys round-trip byte-identical (no float/string coercion).
When it happens
Trigger: capture_task_dependency_binding recorded digests at one point, then the dependency source files changed (commit, checkout, rebuild, manual edit), then validate_dependency_binding was called against the new bytes. Also fires if the binding dict was hand-edited, truncated, or loaded from a stale/serialized form.
Common situations: git checkout between binding capture and arm run changing dependency files; a rebuild of the shipped index; two branches with different dependency trees sharing a binding file; serialization that dropped or renamed the binding keys.
Related errors
- dependency symlink changed while snapshotting: {relative}
- transcript artifact size does not match its results row: {pa
- hidden oracle sandbox does not bind the credited worktree
- hidden oracle mountpoint changed type during verification
- sandboxed candidate setup did not produce an immutable commi
AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12).
Data as JSON: /api/errors/67aa25eabe56441b.
Report an issue: GitHub.