{"record":{"id":"b85ef4175831483d","repo":"abhigyanpatwari/GitNexus","slug":"phase-artifact-must-be-a-readable-regular-non-syml","errorCode":null,"errorMessage":"phase artifact must be a readable regular non-symlink file: {relative}","messagePattern":"phase artifact must be a readable regular non-symlink file: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"eval/workflow_bench/runner_artifacts.py","lineNumber":215,"sourceCode":"    artifact = allowed_artifact.expanduser().absolute()\n    try:\n        relative = PurePosixPath(artifact.relative_to(root).as_posix())\n    except ValueError as exc:\n        raise ValueError(f\"phase artifact escapes the workspace: {allowed_artifact}\") from exc\n    after = workspace_snapshot(root)\n    changed = {path for path in before.keys() | after.keys() if before.get(path) != after.get(path)}\n    artifact_key = relative.as_posix()\n    artifact_state = after.get(artifact_key)\n    if before.get(artifact_key) == artifact_state:\n        raise ValueError(f\"phase did not create or change its required artifact: {relative}\")\n    if artifact_state is None or not artifact_state.startswith(\"f:\"):\n        raise ValueError(f\"phase artifact must be a regular non-symlink file: {relative}\")\n\n    try:\n        metadata = artifact.lstat()\n        descriptor = os.open(artifact, os.O_RDONLY | getattr(os, \"O_NOFOLLOW\", 0))\n    except OSError as exc:\n        raise ValueError(f\"phase artifact must be a readable regular non-symlink file: {relative}\") from exc\n    try:\n        opened = os.fstat(descriptor)\n        if (\n            stat.S_ISLNK(metadata.st_mode)\n            or not stat.S_ISREG(metadata.st_mode)\n            or not stat.S_ISREG(opened.st_mode)\n            or metadata.st_dev != opened.st_dev\n            or metadata.st_ino != opened.st_ino\n        ):\n            raise ValueError(f\"phase artifact must be a regular non-symlink file: {relative}\")\n    finally:\n        os.close(descriptor)\n\n    allowed = {artifact_key}\n    parent = relative.parent\n    while parent.parts:\n        parent_key = parent.as_posix()\n        if parent_key not in before and after.get(parent_key, \"\").startswith(\"d:\"):","sourceCodeStart":197,"sourceCodeEnd":233,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/d540b00184d71a896261ee02670da9a92d59d8f7/eval/workflow_bench/runner_artifacts.py#L197-L233","documentation":"Raised by enforce_phase_workspace (runner_artifacts.py:215) when os.open(artifact, O_RDONLY|O_NOFOLLOW) raises OSError — the artifact cannot be opened for reading. This is the readable-file guard before the TOCTOU check; an unreadable artifact (permissions, ACL, special file) cannot be verified and is rejected.","triggerScenarios":"artifact.lstat() succeeds but os.open fails: the file mode lacks read permission for the benchmark user, an ACL denies open, or the path is a special file (FIFO/device) that cannot be O_RDONLY-opened in the expected way. O_NOFOLLOW also fails with ELOOP if the path is a symlink.","commonSituations":"The model writes the artifact chmod 000 or 600 owned by another user; an SELinux/AppArmor policy denies the read; the artifact path is actually a symlink (O_NOFOLLOW ELOOP); the file is on a read-only mount that became inaccessible.","solutions":["Check the file's permissions and ownership (ls -l <artifact>); chmod +r or chown so the benchmark user can read it.","Ensure the artifact is a real file, not a symlink — re-run the phase with a prompt that writes a regular file.","On locked-down systems, inspect audit logs (ausearch -m AVC) for a denial on the open."],"exampleFix":"# before: model writes the artifact unreadable\nwith open(artifact, 'w') as f: f.write(plan)\nos.chmod(artifact, 0o000)\n\n# after: leave it world-readable\nwith open(artifact, 'w') as f: f.write(plan)\nos.chmod(artifact, 0o644)","handlingStrategy":"validation","validationCode":"import os\nfrom pathlib import Path\n\nartifact = Path(allowed_artifact).expanduser().absolute()\nassert artifact.exists(), f\"artifact missing: {artifact}\"\nassert os.access(artifact, os.R_OK), f\"artifact not readable: {artifact}\"\n# O_NOFOLLOW will fail on a symlink — reject up front\nassert not artifact.is_symlink(), f\"artifact is a symlink: {artifact}\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Ensure the artifact is world-readable after the phase writes it (chmod 644).","Forbid symlinks at the artifact path.","Run the harness as a user with read access to the worktree."],"tags":["phase-boundary","artifact","permissions"],"backgroundTag":null,"analyzedSha":"d540b00184d71a896261ee02670da9a92d59d8f7","analyzedAt":"2026-08-12T19:50:25.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}