abhigyanpatwari/GitNexus · error · ValueError
plan artifact must be a regular file: {path}
Error message
plan artifact must be a regular file: {path} What it means
Raised by snapshot_plan_docs (runner_artifacts.py:271) when a .md/.html file under docs/plans is not a regular file (and not a symlink, which error 478 catches first). Plan artifacts must be regular files so they can be hashed; a FIFO, device node, socket, or other special file is rejected before the hash.
Source
Thrown at eval/workflow_bench/runner_artifacts.py:271
def snapshot_plan_docs(worktree: Path) -> dict[Path, str]:
"""Hash direct, regular plan artifacts without following links."""
plans = worktree / "docs" / "plans"
if not plans.exists():
return {}
if plans.is_symlink() or not plans.is_dir():
raise ValueError(f"plan directory must be a real directory: {plans}")
snapshot: dict[Path, str] = {}
for path in sorted(plans.iterdir()):
if path.suffix.lower() not in {".md", ".html"}:
continue
metadata = path.lstat()
if stat.S_ISLNK(metadata.st_mode):
raise ValueError(f"plan artifact cannot be a symlink: {path}")
if not stat.S_ISREG(metadata.st_mode):
raise ValueError(f"plan artifact must be a regular file: {path}")
descriptor = os.open(path, os.O_RDONLY | getattr(os, "O_NOFOLLOW", 0))
try:
opened = os.fstat(descriptor)
if not stat.S_ISREG(opened.st_mode) or opened.st_dev != metadata.st_dev or opened.st_ino != metadata.st_ino:
raise ValueError(f"plan artifact changed while opening: {path}")
with os.fdopen(descriptor, "rb", closefd=False) as handle:
snapshot[path] = hashlib.file_digest(handle, "sha256").hexdigest()
after = os.fstat(descriptor)
if (opened.st_size, opened.st_mtime_ns) != (after.st_size, after.st_mtime_ns):
raise ValueError(f"plan artifact changed while hashing: {path}")
finally:
os.close(descriptor)
return snapshot
def new_plan_doc(worktree: Path, before: dict[Path, str]) -> Path:
"""Return the sole new or modified plan, rejecting ambiguous evidence."""
View on GitHub (pinned to d540b00184)
Solutions
- Inspect the offending path (ls -l <path>) and remove the special file; recreate a regular file in its place.
- Ensure the planning phase writes plan content via normal file APIs (open/write), not mknod/mkfifo.
- Re-clone the worktree if the special file was committed by mistake.
Example fix
# before mkfifo docs/plans/plan.md # or mknod # after rm docs/plans/plan.md cat > docs/plans/plan.md <<'EOF' # Plan ... EOF
Defensive patterns
Strategy: validation
Validate before calling
import stat
from pathlib import Path
plans = Path(worktree) / "docs" / "plans"
if plans.is_dir():
for p in plans.iterdir():
if p.suffix.lower() in {".md", ".html"}:
mode = p.lstat().st_mode
assert stat.S_ISREG(mode), (
f"plan artifact is not a regular file: {p} (mode={stat.S_IFMT(mode):o})") Type guard
import stat
from pathlib import Path
def all_plans_are_regular_files(worktree) -> bool:
plans = Path(worktree) / "docs" / "plans"
if not plans.is_dir():
return True
for p in plans.iterdir():
if p.suffix.lower() not in {".md", ".html"}:
continue
mode = p.lstat().st_mode
if not stat.S_ISREG(mode):
return False
return True Prevention
- Write plan content via normal file APIs (open/write), never mknod/mkfifo.
- Re-clone the worktree if a special file was committed by mistake.
- Inspect any non-regular entry under docs/plans with ls -l before benchmarking.
When it happens
Trigger: path.lstat().st_mode is neither S_ISLNK (caught at 269) nor S_ISREG for a .md/.html entry. The model or setup created a special file (mkfifo, mknod) named like a plan, or the filesystem reports a degenerate type.
Common situations: A misbehaving tool creates a FIFO or device node where a plan file is expected; a corrupted filesystem entry; a test fixture that accidentally commits a special file.
Related errors
- plan directory must be a real directory: {plans}
- plan artifact cannot be a symlink: {path}
- Unsupported analyzer runtime payload entry: ${absolutePath}
- Analyzer build or dependency runtime changed during analysis
- Search index build failed with an integrity error and the an
AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12).
Data as JSON: /api/errors/591539aefc72cbce.
Report an issue: GitHub.