abhigyanpatwari/GitNexus · error · SandboxError
dependency symlink must be a bounded relative link: {relativ
Error message
dependency symlink must be a bounded relative link: {relative} What it means
Raised by _copy_symlink when the readlink target is empty, is an absolute path (starts with '/'), or contains a NUL byte. The snapshot only stores bounded relative links because absolute links would escape the sandbox workspace at mount time and the snapshot must be reproducible independent of the host's absolute layout. This is a security-containment guard as much as a consistency one.
Source
Thrown at eval/workflow_bench/task_assets.py:474
sha256=digest.hexdigest(),
mode=captured_mode,
)
)
def _copy_symlink(
self,
parent_descriptor: int,
name: str,
relative: PurePosixPath,
before: os.stat_result,
) -> None:
try:
target = os.readlink(name, dir_fd=parent_descriptor)
target_bytes = target.encode("utf-8")
except (OSError, UnicodeEncodeError) as exc:
raise SandboxError(f"dependency symlink is unreadable or not UTF-8: {relative}") from exc
if not target or PurePosixPath(target).is_absolute() or "\x00" in target:
raise SandboxError(f"dependency symlink must be a bounded relative link: {relative}")
if len(target_bytes) > MAX_TASK_ASSET_PATH_BYTES:
raise SandboxError(f"dependency symlink target exceeds the path limit: {relative}")
if self.budget.total_bytes + len(target_bytes) > MAX_TASK_ASSET_BYTES:
raise SandboxError("sandbox_copy exceeds the total byte limit")
destination = self.destination / Path(*relative.parts)
os.symlink(target, destination)
after = os.stat(name, dir_fd=parent_descriptor, follow_symlinks=False)
if (
_mutation_identity(before) != _mutation_identity(after)
or os.readlink(
name,
dir_fd=parent_descriptor,
)
!= target
):
raise SandboxError(f"dependency symlink changed while snapshotting: {relative}")
self.total_bytes += len(target_bytes)
self.budget.total_bytes += len(target_bytes)View on GitHub (pinned to d540b00184)
Solutions
- Recreate offending symlinks as relative links: `ln -sfn ../<package> node_modules/<link>` using a path relative to the link's own directory.
- If using npm/pnpm/yarn, reinstall dependencies inside the repo so the package manager writes relative links: `rm -rf node_modules && npm install`.
- Audit with: `find <dep-source> -type l -exec sh -c 'readlink "$1" | grep -q ^/ && echo "$1"' _ {} \;` to list absolute-target links.
- For NUL-byte or empty targets, delete and recreate the link cleanly.
Example fix
# before node_modules/.foo -> /usr/lib/node_modules/foo # after rm node_modules/.foo ln -s ../foo node_modules/.foo # relative, bounded
Defensive patterns
Strategy: validation
Validate before calling
from pathlib import Path, PurePosixPath
import os
def validate_symlinks_bounded_relative(dep_source: Path) -> None:
for current, dirs, files in os.walk(dep_source, followlinks=False):
for name in dirs + files:
p = Path(current) / name
if p.is_symlink():
target = os.readlink(p)
if not target or PurePosixPath(target).is_absolute() or "\x00" in target:
raise ValueError(f"symlink must be bounded relative: {p} -> {target!r}")
for d in task.get("sandbox_dependencies", []):
validate_symlinks_bounded_relative(repo_path / d["source"]) Type guard
from pathlib import PurePosixPath
import os
from pathlib import Path
def symlink_target_is_bounded_relative(p: Path) -> bool:
try:
t = os.readlink(p)
except OSError:
return False
return bool(t) and not PurePosixPath(t).is_absolute() and "\x00" not in t Try / catch
from eval.workflow_bench.propposer_sandbox import SandboxError
try:
snapshot = cache.prepare(task, repo=repo, resolved_sha=sha)
except SandboxError as exc:
if "bounded relative link" in str(exc):
# recreate offending links as relative, then re-run
raise
raise Prevention
- Install dependencies inside the repo so package managers write relative links.
- Audit with `find <dep-source> -type l -exec sh -c 'readlink "$1" | grep -q ^/ && echo "$1"' _ {} \;`.
- Never hand-create absolute symlinks inside dependency sources.
When it happens
Trigger: A sandbox_dependency source tree contains a symlink pointing to an absolute path (e.g. `/usr/lib/node_modules/foo`), a symlink created with `ln -s '' ...` (empty target), or a malformed link whose target string embeds a NUL byte. Common with system-installed npm packages that symlink into global directories.
Common situations: node_modules created by a system package manager (apt/brew) that links into /usr/lib. A developer hand-created symlink with an absolute target for convenience. Symlinks pointing to /tmp or /home during local dev that got committed or vendored.
Related errors
- results artifact parent must be a real directory: {current}
- {label} escapes its allowed repository root: {relative}
- dependency source must stay inside the repository: {source_p
- dependency target must stay inside the clone: {target_path}
- dependency symlink escapes the sandbox workspace: {entry.pat
AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12).
Data as JSON: /api/errors/d2a3a41a1be02253.
Report an issue: GitHub.