abhigyanpatwari/GitNexus · critical · SandboxError
sandbox_copy must not traverse a symlink: {relative}
Error message
sandbox_copy must not traverse a symlink: {relative} What it means
Raised by _open_child when the pre-open os.stat shows S_ISLNK on any path component of a declared sandbox_copy path. The snapshot walker never crosses symlinks because a symlink could redirect capture outside the repo root, breaking the containment contract that SandboxError guards.
Source
Thrown at eval/workflow_bench/task_assets.py:630
return current
except BaseException:
os.close(current)
raise
def _open_child(
parent_descriptor: int,
name: str,
relative: PurePosixPath,
*,
require_directory: bool = False,
) -> int:
try:
metadata = os.stat(name, dir_fd=parent_descriptor, follow_symlinks=False)
except OSError as exc:
raise SandboxError(f"sandbox_copy path is unavailable: {relative}: {exc}") from exc
if stat.S_ISLNK(metadata.st_mode):
raise SandboxError(f"sandbox_copy must not traverse a symlink: {relative}")
if require_directory and not stat.S_ISDIR(metadata.st_mode):
raise SandboxError(f"sandbox_copy parent must be a directory: {relative}")
if not (stat.S_ISDIR(metadata.st_mode) or stat.S_ISREG(metadata.st_mode)):
raise SandboxError(f"sandbox_copy accepts only regular files and directories: {relative}")
flags = os.O_RDONLY | getattr(os, "O_CLOEXEC", 0) | getattr(os, "O_NOFOLLOW", 0)
if stat.S_ISDIR(metadata.st_mode):
flags |= os.O_DIRECTORY
else:
flags |= getattr(os, "O_NONBLOCK", 0)
try:
descriptor = os.open(name, flags, dir_fd=parent_descriptor)
except OSError as exc:
raise SandboxError(f"sandbox_copy path changed or is unreadable: {relative}: {exc}") from exc
opened = os.fstat(descriptor)
if not (stat.S_ISDIR(opened.st_mode) or stat.S_ISREG(opened.st_mode)):
os.close(descriptor)
raise SandboxError(f"sandbox_copy accepts only regular files and directories: {relative}")
if (View on GitHub (pinned to d540b00184)
Solutions
- Resolve the symlink target and declare the real path it points to
- Remove the symlink from the worktree at the captured SHA, or exclude that subtree from the declaration
- If the linked content is genuinely needed, materialize it as a regular file/dir before capture
Example fix
// before (declaration points at a symlink) // sandbox_copy: // - src/build # 'build' is a symlink -> 'dist/build' // after // sandbox_copy: // - src/dist/build # the real directory
Defensive patterns
Strategy: validation
Validate before calling
import os, stat
from pathlib import Path
def find_symlinks_under(root: Path, declared: list[str]) -> list[str]:
hits = []
for decl in declared:
base = root / decl
if base.is_symlink():
hits.append(str(decl)); continue
cur = base.parent
parts = list(Path(decl).parts)
walker = root
for part in parts:
try:
if os.path.islink(walker / part):
hits.append(f"{decl} (symlink at {walker/part})"); break
except OSError:
break
walker = walker / part
return hits
# abort prepare if hits is non-empty Try / catch
from eval.workflow_bench.proposer_sandbox import SandboxError
try:
snapshot = cache.prepare(task, repo=repo, resolved_sha=sha)
except SandboxError as exc:
if "must not traverse a symlink" in str(exc):
raise SystemExit(f"declaration crosses a symlink; resolve the real path: {exc}") from exc
raise Prevention
- Resolve all declaration paths to their real (non-symlink) targets before capture
- Avoid declaring installed-package directories that contain symlinks (e.g. node_modules/.bin)
- Run `find <repo> -type l` over each declared root before preparing the snapshot
When it happens
Trigger: A sandbox_copy declaration (or one of its parent directories) is a symlink in the worktree at the resolved SHA; e.g. a top-level convenience link like build -> dist/build, or an installed package alias.
Common situations: Monorepos with cross-package symlinks; packages that create relative symlinks during install; a task pin captured after npm install wrote symlinks into the copied tree.
Related errors
- sandbox_copy must not traverse a symlink: {child_relative}
- dependency symlink escapes the sandbox workspace: {entry.pat
- sandbox_copy {role}: {relative}
- sandbox_copy target cannot traverse a symlink: {parent}
- task asset snapshot contains an unexpected symlink: {path}
AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12).
Data as JSON: /api/errors/00954a1a5e2a5a61.
Report an issue: GitHub.