abhigyanpatwari/GitNexus · error · ValueError

phase artifact must be a regular non-symlink file: {relative

Error message

phase artifact must be a regular non-symlink file: {relative}

What it means

Raised by enforce_phase_workspace (runner_artifacts.py:209) when the declared artifact exists in the after snapshot but its state does not start with 'f:' (i.e. it is not a regular file). The phase artifact must be a regular, non-symlink file so its content can be hashed and diffed; a directory, symlink, socket, or device node as the artifact is rejected.

Source

Thrown at eval/workflow_bench/runner_artifacts.py:209

    *,
    allowed_artifact: Path,
) -> None:
    """Require a phase to change only its one explicit workspace artifact."""

    root = worktree.expanduser().absolute()
    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)

View on GitHub (pinned to d540b00184)

Solutions

  1. Inspect the after snapshot entry for artifact_key to see its actual type (d/l/s prefix); have the model write a regular file instead of a directory or symlink.
  2. If the artifact is genuinely missing (artifact_state None), the phase did not produce it — see error 470 remedies.
  3. Adjust the prompt to require a regular file at the exact path and forbid symlinks/directories.

Example fix

# before: model creates a directory or symlink at the artifact path
mkdir docs/plans/plan.md   # or: ln -s ../template.md docs/plans/plan.md

# after: model writes a regular file
cat > docs/plans/plan.md <<'EOF'
# Plan
...
EOF
Defensive patterns

Strategy: validation

Validate before calling

import os, stat
from pathlib import Path

artifact = Path(allowed_artifact).expanduser().absolute()
assert artifact.exists(), f"artifact missing: {artifact}"
mode = artifact.lstat().st_mode
assert stat.S_ISREG(mode), f"artifact is not a regular file: {artifact} (mode={stat.S_IFMT(mode):o})"
assert not stat.S_ISLNK(mode), f"artifact is a symlink: {artifact}"
assert not stat.S_ISDIR(mode), f"artifact is a directory: {artifact}"

Type guard

import stat
from pathlib import Path

def is_regular_nonsymlink_file(path) -> bool:
    try:
        mode = Path(path).lstat().st_mode
    except OSError:
        return False
    return stat.S_ISREG(mode) and not stat.S_ISLNK(mode)

Prevention

When it happens

Trigger: artifact_state is None (artifact missing) or starts with 'd:'/'l:'/'s:' (directory/symlink/special) at line 208. The model created a directory where a file was expected, replaced the file with a symlink, or did not create the file at all (artifact_state None falls through to this same message).

Common situations: The model did mkdir where it should have written a file; the model symlinked the artifact to an existing doc; the artifact_key is a directory path; the model named the artifact with no extension so a tool treated it as a dir.

Related errors


AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12). Data as JSON: /api/errors/e0a74b70d82b16de. Report an issue: GitHub.