{"record":{"id":"67aa25eabe56441b","repo":"abhigyanpatwari/GitNexus","slug":"sandbox-dependency-content-changed-after-task-bind","errorCode":null,"errorMessage":"sandbox dependency content changed after task binding","messagePattern":"sandbox dependency content changed after task binding","errorType":"exception","errorClass":"SandboxError","httpStatus":null,"severity":"error","filePath":"eval/workflow_bench/task_assets.py","lineNumber":961,"sourceCode":"    manifest_digest = hashlib.sha256(\n        json.dumps(manifest_payload, sort_keys=True, separators=(\",\", \":\")).encode()\n    ).hexdigest()\n    return content_digest, manifest_digest\n\n\ndef _validate_dependency_binding_values(\n    binding: Mapping[str, Any],\n    *,\n    content_digest: str,\n    manifest_digest: str,\n) -> None:\n    expected = {\n        DEPENDENCY_CONTENT_BINDING_FIELD: content_digest,\n        DEPENDENCY_MANIFEST_BINDING_FIELD: manifest_digest,\n    }\n    supplied = {field: binding.get(field) for field in expected}\n    if supplied != expected:\n        raise SandboxError(\"sandbox dependency content changed after task binding\")\n\n\ndef _snapshot_digest(\n    *,\n    repo_identity: Path,\n    resolved_sha: str,\n    declarations: tuple[str, ...],\n    manifest_digest: str,\n    dependency_content_digest: str,\n    dependency_manifest_digest: str,\n) -> str:\n    payload = {\n        \"declarations\": declarations,\n        \"dependency_content_digest\": dependency_content_digest,\n        \"dependency_manifest_digest\": dependency_manifest_digest,\n        \"manifest_digest\": manifest_digest,\n        \"repo_identity\": str(repo_identity),\n        \"resolved_sha\": resolved_sha,","sourceCodeStart":943,"sourceCodeEnd":979,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/d540b00184d71a896261ee02670da9a92d59d8f7/eval/workflow_bench/task_assets.py#L943-L979","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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)."],"exampleFix":"# before: binding captured once, repo later moved\nbinding = capture_task_dependency_binding(task, repo=repo, resolved_sha=old_sha)\ngit_checkout('main')              # dependency bytes changed\nsnapshot.validate_dependency_binding(binding)   # -> mismatch\n\n# after: capture and validate at the same sha\nsnapshot = cache.prepare(task, repo=repo, resolved_sha=sha)\nbinding = snapshot.dependency_binding\n# ... no repo mutation in between ...\nsnapshot.validate_dependency_binding(binding)","handlingStrategy":"validation","validationCode":"from .task_assets import capture_task_dependency_binding, TaskAssetCache\n\ndef fresh_binding(task, *, repo, resolved_sha) -> dict[str, str]:\n    # Always (re)capture at the exact sha you will run against.\n    return capture_task_dependency_binding(task, repo=repo, resolved_sha=resolved_sha)\n\n# Compare against any stored binding *before* staging:\nexpected = snapshot.dependency_binding\nif stored != expected:\n    raise ValueError('stored dependency binding is stale; recapture before staging')","typeGuard":"def binding_matches(binding: Mapping[str, object], snapshot: 'TaskAssetSnapshot') -> bool:\n    return binding == snapshot.dependency_binding","tryCatchPattern":"from .proposer_sandbox import SandboxError\n\ntry:\n    snapshot.validate_dependency_binding(binding)\nexcept SandboxError as exc:\n    if 'dependency content changed' in str(exc):\n        # Re-capture at the current sha and update the stored binding; do NOT\n        # edit the binding by hand.\n        binding = capture_task_dependency_binding(task, repo=repo, resolved_sha=sha)\n        snapshot.validate_dependency_binding(binding)\n    else:\n        raise","preventionTips":["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)."],"tags":["integrity","dependencies","hashing","sandbox"],"backgroundTag":null,"analyzedSha":"d540b00184d71a896261ee02670da9a92d59d8f7","analyzedAt":"2026-08-12T19:50:25.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}