abhigyanpatwari/GitNexus · error · ValueError
phase artifact must be a readable regular non-symlink file:
Error message
phase artifact must be a readable regular non-symlink file: {relative} What it means
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.
Source
Thrown at eval/workflow_bench/runner_artifacts.py:215
artifact = allowed_artifact.expanduser().absolute()
try:
relative = PurePosixPath(artifact.relative_to(root).as_posix())
except ValueError as exc:
raise ValueError(f"phase artifact escapes the workspace: {allowed_artifact}") from exc
after = workspace_snapshot(root)
changed = {path for path in before.keys() | after.keys() if before.get(path) != after.get(path)}
artifact_key = relative.as_posix()
artifact_state = after.get(artifact_key)
if before.get(artifact_key) == artifact_state:
raise ValueError(f"phase did not create or change its required artifact: {relative}")
if artifact_state is None or not artifact_state.startswith("f:"):
raise ValueError(f"phase artifact must be a regular non-symlink file: {relative}")
try:
metadata = artifact.lstat()
descriptor = os.open(artifact, os.O_RDONLY | getattr(os, "O_NOFOLLOW", 0))
except OSError as exc:
raise ValueError(f"phase artifact must be a readable regular non-symlink file: {relative}") from exc
try:
opened = os.fstat(descriptor)
if (
stat.S_ISLNK(metadata.st_mode)
or not stat.S_ISREG(metadata.st_mode)
or not stat.S_ISREG(opened.st_mode)
or metadata.st_dev != opened.st_dev
or metadata.st_ino != opened.st_ino
):
raise ValueError(f"phase artifact must be a regular non-symlink file: {relative}")
finally:
os.close(descriptor)
allowed = {artifact_key}
parent = relative.parent
while parent.parts:
parent_key = parent.as_posix()
if parent_key not in before and after.get(parent_key, "").startswith("d:"):View on GitHub (pinned to d540b00184)
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.
Example fix
# before: model writes the artifact unreadable with open(artifact, 'w') as f: f.write(plan) os.chmod(artifact, 0o000) # after: leave it world-readable with open(artifact, 'w') as f: f.write(plan) os.chmod(artifact, 0o644)
Defensive patterns
Strategy: validation
Validate before calling
import os
from pathlib import Path
artifact = Path(allowed_artifact).expanduser().absolute()
assert artifact.exists(), f"artifact missing: {artifact}"
assert os.access(artifact, os.R_OK), f"artifact not readable: {artifact}"
# O_NOFOLLOW will fail on a symlink — reject up front
assert not artifact.is_symlink(), f"artifact is a symlink: {artifact}" Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- phase did not create or change its required artifact: {relat
- phase artifact must be a regular non-symlink file: {relative
- Could not read ${GITNEXUS_RC_FILENAME}: ${(err as Error).mes
- candidate destination is unreadable: {relative}: {exc}
- candidate overlay directory is unreadable: {directory}: {exc
AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12).
Data as JSON: /api/errors/b85ef4175831483d.
Report an issue: GitHub.