{"record":{"id":"9336375b5864e98b","repo":"abhigyanpatwari/GitNexus","slug":"sandbox-copy-path-changed-while-opening-relative","errorCode":null,"errorMessage":"sandbox_copy path changed while opening: {relative}","messagePattern":"sandbox_copy path changed while opening: (.+?)","errorType":"exception","errorClass":"SandboxError","httpStatus":null,"severity":"critical","filePath":"eval/workflow_bench/task_assets.py","lineNumber":658,"sourceCode":"    try:\n        descriptor = os.open(name, flags, dir_fd=parent_descriptor)\n    except OSError as exc:\n        raise SandboxError(f\"sandbox_copy path changed or is unreadable: {relative}: {exc}\") from exc\n    opened = os.fstat(descriptor)\n    if not (stat.S_ISDIR(opened.st_mode) or stat.S_ISREG(opened.st_mode)):\n        os.close(descriptor)\n        raise SandboxError(f\"sandbox_copy accepts only regular files and directories: {relative}\")\n    if (\n        opened.st_dev,\n        opened.st_ino,\n        stat.S_IFMT(opened.st_mode),\n    ) != (\n        metadata.st_dev,\n        metadata.st_ino,\n        stat.S_IFMT(metadata.st_mode),\n    ):\n        os.close(descriptor)\n        raise SandboxError(f\"sandbox_copy path changed while opening: {relative}\")\n    return descriptor\n\n\ndef _validate_dependency_symlinks(\n    container: Path,\n    entries: tuple[AssetManifestEntry, ...],\n    *,\n    mount_target: PurePosixPath,\n) -> None:\n    snapshot_boundary = (container / \"payload\").resolve(strict=True)\n    manifest_boundary = PurePosixPath(\"payload\")\n    sandbox_boundary = PurePosixPath(SANDBOX_WORKSPACE)\n    sandbox_mount = sandbox_boundary / mount_target\n    for entry in entries:\n        if entry.kind != \"symlink\":\n            continue\n        target = PurePosixPath(entry.link_target)\n        relative_to_payload = entry.path.relative_to(manifest_boundary)","sourceCodeStart":640,"sourceCodeEnd":676,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/d540b00184d71a896261ee02670da9a92d59d8f7/eval/workflow_bench/task_assets.py#L640-L676","documentation":"_open_child compares (st_dev, st_ino, S_IFMT) from the pre-open stat against the post-open fstat. A mismatch means the directory entry was substituted (rename, or unlink+recreate) during the open window — a classic TOCTOU swap that the containment contract refuses to silently accept.","triggerScenarios":"A component is swapped between stat and open; concurrent git checkout, rsync, or build tooling rewriting the tree during capture.","commonSituations":"Live worktree edits during benchmarking; a worktree shared across arms without coordination.","solutions":["Freeze the worktree (read-only bind mount, or a dedicated clone per run)","Re-run capture after quiescing all writers","Use one private worktree per concurrent arm so no cross-arm mutation can occur"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"from eval.workflow_bench.proposer_sandbox import SandboxError\n\ntry:\n    snapshot = cache.prepare(task, repo=repo, resolved_sha=sha)\nexcept SandboxError as exc:\n    if \"path changed while opening\" in str(exc):\n        raise SystemExit(f\"TOCTOU inode swap during capture; freeze the worktree: {exc}\") from exc\n    raise","preventionTips":["Freeze the worktree (read-only bind mount) before capture","Use a dedicated clone per run instead of mutating a shared one","Stop git checkout/rsync/builds against the worktree during capture"],"tags":["sandbox","toctou","race","inode-swap"],"backgroundTag":null,"analyzedSha":"d540b00184d71a896261ee02670da9a92d59d8f7","analyzedAt":"2026-08-12T19:50:25.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}