{"record":{"id":"104cadcf17fd386e","repo":"abhigyanpatwari/GitNexus","slug":"workspace-snapshot-directory-is-unreadable-direc","errorCode":null,"errorMessage":"workspace snapshot directory is unreadable: {directory}: {exc}","messagePattern":"workspace snapshot directory is unreadable: (.+?): (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"eval/workflow_bench/runner_artifacts.py","lineNumber":143,"sourceCode":"    WORKSPACE_SNAPSHOT_BOOTSTRAP_NOISE).\"\"\"\n\n    root = worktree.expanduser().absolute()\n    mode = root.lstat().st_mode\n    if stat.S_ISLNK(mode) or not stat.S_ISDIR(mode) or root.resolve(strict=True) != root:\n        raise ValueError(f\"workspace snapshot root must be a real directory: {root}\")\n\n    snapshot: dict[str, str] = {}\n    pending: list[tuple[Path, PurePosixPath]] = [(root, PurePosixPath())]\n    entry_count = 0\n    path_bytes = 0\n    file_bytes = 0\n    nofollow = getattr(os, \"O_NOFOLLOW\", 0)\n    while pending:\n        directory, relative_dir = pending.pop()\n        try:\n            children = sorted(os.scandir(directory), key=lambda entry: entry.name, reverse=True)\n        except OSError as exc:\n            raise ValueError(f\"workspace snapshot directory is unreadable: {directory}: {exc}\") from exc\n        for entry in children:\n            relative = relative_dir / entry.name\n            if _is_bootstrap_noise(relative):\n                continue\n            entry_count += 1\n            path_bytes += len(relative.as_posix().encode())\n            if entry_count > MAX_WORKSPACE_SNAPSHOT_ENTRIES or path_bytes > MAX_WORKSPACE_SNAPSHOT_PATH_BYTES:\n                raise ValueError(\"workspace snapshot exceeds its bounded entry or path limit\")\n            metadata = entry.stat(follow_symlinks=False)\n            permissions = stat.S_IMODE(metadata.st_mode)\n            if stat.S_ISDIR(metadata.st_mode):\n                snapshot[relative.as_posix()] = f\"d:{permissions:o}\"\n                pending.append((Path(entry.path), relative))\n                continue\n            if stat.S_ISLNK(metadata.st_mode):\n                snapshot[relative.as_posix()] = f\"l:{permissions:o}:{os.readlink(entry.path)}\"\n                continue\n            if not stat.S_ISREG(metadata.st_mode):","sourceCodeStart":125,"sourceCodeEnd":161,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/d540b00184d71a896261ee02670da9a92d59d8f7/eval/workflow_bench/runner_artifacts.py#L125-L161","documentation":"Raised inside the workspace_snapshot walk (runner_artifacts.py:143) when os.scandir(directory) raises OSError for a subdirectory that lstat earlier reported as a directory. The walker re-wraps the OS error as a ValueError so callers see a single integrity-failure category. This guards against a workspace that mutates its directory structure (revoked permissions, disappeared mount) while being hashed.","triggerScenarios":"A subdirectory passed the earlier stat S_ISDIR check but os.scandir now fails: permissions were revoked (chmod 000), a fuse/network mount dropped, or the directory was deleted between the stat and the scandir. Also triggered by an unreadable directory the benchmark user lacks rx on.","commonSituations":"A task setup or model run that chmods a directory to 000 inside the worktree; running the harness as a user without read on a vendored node_modules; a flaky network filesystem backing the worktree.","solutions":["Inspect the {directory} in the message and check its permissions/ownership (ls -ld <dir>); chmod +rx or chown as needed.","Ensure no concurrent process is deleting or re-permissioning worktree subdirs during the snapshot (the snapshot is taken at phase boundaries).","Run the snapshot outside any fuse/network mount; keep the worktree on local disk."],"exampleFix":"# before: a phase leaves a dir unreadable\nos.chmod(\"worktree/secret\", 0o000)\n\n# after: restore read/exec so the snapshot can scan it\nos.chmod(\"worktree/secret\", 0o755)","handlingStrategy":"validation","validationCode":"import os, stat\n\ndef assert_scannable(root):\n    \"\"\"Walk and confirm every subdir is rx-accessible before snapshotting.\"\"\"\n    for dirpath, dirnames, _ in os.walk(root):\n        try:\n            os.scandir(dirpath).close()\n        except OSError as exc:\n            raise PermissionError(f\"unreadable dir {dirpath}: {exc}\") from exc\n        for d in dirnames:\n            mode = os.lstat(os.path.join(dirpath, d)).st_mode\n            if not os.access(os.path.join(dirpath, d), os.R_OK | os.X_OK):\n                raise PermissionError(f\"no rx on {os.path.join(dirpath, d)}\")","typeGuard":null,"tryCatchPattern":"try:\n    snapshot = workspace_snapshot(root)\nexcept ValueError as exc:\n    if \"directory is unreadable\" in str(exc):\n        # fix permissions on the named directory, then retry ONCE\n        path = str(exc).split(\": \")[1]\n        os.chmod(path, 0o755)\n        snapshot = workspace_snapshot(root)\n    else:\n        raise","preventionTips":["Ensure the benchmark user has rx on every directory under the worktree.","Stop background processes that re-permission or delete worktree subdirs during phase boundaries.","Run the snapshot only when the phase is quiescent."],"tags":["filesystem","permissions","workspace-snapshot"],"backgroundTag":null,"analyzedSha":"d540b00184d71a896261ee02670da9a92d59d8f7","analyzedAt":"2026-08-12T19:50:25.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}