abhigyanpatwari/GitNexus · error · SandboxError
results directory must be a real non-symlink directory: {roo
Error message
results directory must be a real non-symlink directory: {root} What it means
After lstat succeeds, _real_results_root checks the mode: if it is a symlink (stat.S_ISLNK) or not a directory (not stat.S_ISDIR) the path is rejected. lstat is used intentionally so a symlink-to-a-directory is still treated as a symlink and refused — the harness must bind a real directory inode, not an indirectable link.
Source
Thrown at eval/workflow_bench/evolve.py:295
def _bounded_regular_text(path: Path, limit: int = MAX_EVIDENCE_FILE_BYTES) -> str:
mode = path.lstat().st_mode
if path.is_symlink() or not stat.S_ISREG(mode):
raise SandboxError(f"evidence source must be a regular non-symlink file: {path}")
with path.open("rb") as handle:
if path.stat().st_size > limit:
handle.seek(-limit, os.SEEK_END)
return handle.read(limit).decode(errors="replace")
def _real_results_root(results_dir: Path) -> Path:
root = results_dir.expanduser().absolute()
try:
metadata = root.lstat()
except OSError as exc:
raise SandboxError(f"results directory is unavailable: {root}: {exc}") from exc
if stat.S_ISLNK(metadata.st_mode) or not stat.S_ISDIR(metadata.st_mode):
raise SandboxError(f"results directory must be a real non-symlink directory: {root}")
if root.resolve(strict=True) != root:
raise SandboxError(f"results directory must not traverse symlinks: {root}")
return root
def _results_artifact_path(root: Path, relative_value: str, *, transcript: bool) -> Path:
relative = PurePosixPath(relative_value)
expected_parts = 2 if transcript else 1
if (
relative.is_absolute()
or len(relative.parts) != expected_parts
or any(part in {"", ".", ".."} for part in relative.parts)
or (transcript and relative.parts[0] != "transcripts")
):
raise SandboxError(f"unsafe results artifact path: {relative_value!r}")
current = root
for part in relative.parts[:-1]:
current /= partView on GitHub (pinned to d540b00184)
Solutions
- Check the inode type: `ls -ldH <results_dir>` (note the `-H` follows the argument symlink; you want to see a real dir with no arrow).
- Pass the real directory, not a symlink to it.
- If a file was created in its place, remove it and recreate the directory.
Example fix
# before: ~/results is a symlink
ln -s /mnt/nfs/results ~/results
proposer_evidence_entries(results_dir=Path("~/results").expanduser(), ...)
# after: bind the real directory
proposer_evidence_entries(results_dir=Path("/mnt/nfs/results"), ...) Defensive patterns
Strategy: validation
Validate before calling
import stat
from pathlib import Path
def is_real_results_dir(path: Path) -> bool:
try:
m = path.expanduser().absolute().lstat().st_mode
except OSError:
return False
return stat.S_ISDIR(m) and not stat.S_ISLNK(m) Type guard
import stat
from pathlib import Path
def is_non_symlink_directory(path: Path) -> bool:
m = path.lstat().st_mode
return stat.S_ISDIR(m) and not stat.S_ISLNK(m) Prevention
- Pass the results directory, not the results.jsonl file.
- Do not symlink the results root; bind a real directory inode.
- Resolve the path before passing: realpath must equal the given path.
When it happens
Trigger: results_dir is a regular file (e.g. a results.jsonl passed by mistake instead of its parent dir), a symlink to a directory, or a block/char device.
Common situations: User passes the results file instead of the dir; a convenience symlink (`ln -s /mnt/nfs/results ~/results`) used as the argument; a packaging artifact written over the dir.
Related errors
- results directory must not traverse symlinks: {root}
- evidence source must be a regular non-symlink file: {path}
- results directory is unavailable: {root}: {exc}
- results artifact parent is unavailable: {current}: {exc}
- results artifact parent must be a real directory: {current}
AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12).
Data as JSON: /api/errors/db2e2afeaa05fd75.
Report an issue: GitHub.