abhigyanpatwari/GitNexus · error · SandboxError
dependency symlink is unreadable or not UTF-8: {relative}
Error message
dependency symlink is unreadable or not UTF-8: {relative} What it means
Raised by _SnapshotBuilder._copy_symlink when os.readlink fails (OSError — e.g. permission denied, dangling link on some kernels, ENOENT) or when the link target string cannot be encoded as UTF-8 (UnicodeEncodeError). Symlinks are only followed for sandbox_dependencies (allow_symlinks=True), never for sandbox_copy roots. The snapshot must store the target verbatim, so non-UTF-8 or unreadable links cannot be captured faithfully.
Source
Thrown at eval/workflow_bench/task_assets.py:472
kind="file",
size=copied,
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}")View on GitHub (pinned to d540b00184)
Solutions
- Run `find <dependency-source> -type l -print0 | xargs -0 readlink` and identify any link that errors or prints garbage bytes.
- Remove or recreate offending symlinks so they point to valid UTF-8 relative targets.
- Ensure the harness user has read permission on the parent directory and the symlink entry (chmod +r on the dir if needed).
- If the link was deleted mid-capture, re-run after quiescing the tree.
Example fix
# before — a node_modules symlink with a non-UTF-8 target ls -la node_modules/.bin # fix: recreate the link with a clean relative target rm node_modules/.bin/bad-link ln -s ../some-package/cli.js node_modules/.bin/bad-link
Defensive patterns
Strategy: validation
Validate before calling
from pathlib import Path
import os, stat
def validate_dependency_symlinks_readable(dep_source: Path) -> None:
for current, dirs, files in os.walk(dep_source, followlinks=False):
entries = dirs + files
for name in entries:
p = Path(current) / name
if p.is_symlink():
try:
target = os.readlink(p)
target.encode("utf-8")
except (OSError, UnicodeEncodeError) as exc:
raise ValueError(f"unreadable/non-UTF-8 symlink: {p}: {exc}") from exc
for d in task.get("sandbox_dependencies", []):
validate_dependency_symlinks_readable(repo_path / d["source"]) Type guard
import os
from pathlib import Path
def symlink_is_utf8_readable(p: Path) -> bool:
try:
os.readlink(p).encode("utf-8")
return True
except (OSError, UnicodeEncodeError):
return False 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 "unreadable or not UTF-8" in str(exc):
# locate and recreate the offending link, then re-run
raise
raise Prevention
- Reinstall node_modules with a standard package manager so all links are clean UTF-8.
- Audit dependency symlinks with `find <source> -type l -print0 | xargs -0 -I{} readlink {}` before capture.
- Ensure the harness user has read permission on the source tree.
When it happens
Trigger: A sandbox_dependency source tree contains a symlink whose target is a path with bytes invalid in the current locale, or a symlink the reader lacks permission to readlink, or a symlink that was deleted between listing the parent directory and calling readlink (TOCTOU removal).
Common situations: node_modules contains a symlink to a path with non-UTF-8 bytes (rare on Linux but possible with certain package managers or mounted volumes). A broken/deleted symlink inside a dependency tree. Permission modes that deny readlink to the harness user.
Related errors
- dependency symlink must be a bounded relative link: {relativ
- dependency symlink target exceeds the path limit: {relative}
- dependency symlink changed while snapshotting: {relative}
- {label} must be a real non-symlink directory: {path}
- {label} must be a regular non-symlink file: {path}
AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12).
Data as JSON: /api/errors/739892a2ba827f96.
Report an issue: GitHub.