abhigyanpatwari/GitNexus · critical · SandboxError
target .gitnexus path must be a real directory before graph
Error message
target .gitnexus path must be a real directory before graph preparation
What it means
Precondition guard in _neutralize_target_index_inputs. The clone's '.gitnexus' path, if present, must be a real directory (not a symlink, not a regular file) before the harness removes it and writes neutral control files. A symlinked or file '.gitnexus' is treated as a sandbox-escape attempt (pointing at an external graph) and rejected. An absent '.gitnexus' is fine: the harness simply creates the control files.
Source
Thrown at eval/workflow_bench/sanitized_graph.py:141
while view:
written = os.write(descriptor, view)
if written <= 0:
raise OSError(f"short write while neutralizing {name}")
view = view[written:]
os.fsync(descriptor)
finally:
os.close(descriptor)
def _neutralize_target_index_inputs(root: Path) -> None:
index = root / ".gitnexus"
try:
metadata = index.lstat()
except FileNotFoundError:
metadata = None
if metadata is not None:
if stat.S_ISLNK(metadata.st_mode) or not stat.S_ISDIR(metadata.st_mode):
raise SandboxError("target .gitnexus path must be a real directory before graph preparation")
shutil.rmtree(index)
_replace_control_file(root, ".gitnexusrc", b"{}\n")
_replace_control_file(root, ".gitnexusignore", b"")
def _scrub_source_references(root: Path) -> tuple[str, ...]:
"""Remove graph inputs whose path or stored content references the harness.
The disposable graph seed may contain docs or shipped skill copies outside
the removed harness that name its paths. They are harmless implementation
context in an arm checkout, but indexing them would let graph/MCP queries
recover benchmark-specific hints. Scan the exact <=512 KiB file universe
admitted by the pinned analyzer and remove contaminated inputs before the
graph is built. Target-controlled ignore/config files are not consulted.
"""
marker_bytes = tuple(marker.encode() for marker in GRAPH_MARKERS)
pending: list[tuple[Path, PurePosixPath]] = [(root, PurePosixPath())]View on GitHub (pinned to d540b00184)
Solutions
- Inspect the clone root before neutralization: 'ls -la <clone>/.gitnexus' and confirm it is either absent or a real directory.
- Remove any symlink or regular-file '.gitnexus' from the task fixture or sandbox_copy source.
- Ensure no sandbox_dependency target is '.gitnexus' and no sandbox_copy entry creates it.
- Let the harness build the graph in-sandbox; do not pre-populate .gitnexus by any mechanism.
Example fix
# before (fixture pre-seeds a graph via symlink) ln -s /prebuilt/graph .gitnexus # after (let the harness create and index from scratch) rm .gitnexus
Defensive patterns
Strategy: validation
Validate before calling
from pathlib import Path
import stat
clone = Path("clone-root")
g = clone / ".gitnexus"
if g.is_symlink():
raise SystemExit(".gitnexus is a symlink; remove it")
try:
mode = g.lstat().st_mode
except FileNotFoundError:
pass
else:
if not stat.S_ISDIR(mode):
raise SystemExit(".gitnexus must be a real directory or absent") Type guard
from pathlib import Path
import stat
def gitnexus_is_safe_to_neutralize(clone_root: Path) -> bool:
g = clone_root / ".gitnexus"
try:
mode = g.lstat().st_mode
except FileNotFoundError:
return True
return stat.S_ISDIR(mode) and not stat.S_ISLNK(mode) Try / catch
try:
_neutralize_target_index_inputs(clone_root)
except SandboxError as exc:
if "real directory before graph preparation" in str(exc):
log.error(".gitnexus is a symlink/file (possible escape attempt); remove it")
raise Prevention
- Never pre-populate .gitnexus in a fixture, sandbox_copy, or dependency.
- Let the harness build the graph from scratch inside the sandbox.
- Audit fixtures for any '.gitnexus' symlink or regular file before submission.
When it happens
Trigger: A sanitized clone root contains a '.gitnexus' that lstat reports as a symlink or as a non-directory inode. This typically means a task fixture or sandbox_copy entry planted a '.gitnexus' link/file to smuggle in a prebuilt graph.
Common situations: A task tries to seed a graph by symlinking .gitnexus -> /some/prebuilt; a fixture created .gitnexus as a marker file; a sandbox_copy of a parent directory dragged in a .gitnexus regular file; a previous failed run left a stale file (less likely, since rmtree would have handled a dir).
Related errors
- {label} must be a real non-symlink directory: {path}
- {label} must be a regular non-symlink file: {path}
- evidence source must be a regular non-symlink file: {path}
- results directory must not traverse symlinks: {root}
- results artifact parent must be a real directory: {current}
AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12).
Data as JSON: /api/errors/decccb29da8c7fc5.
Report an issue: GitHub.