abhigyanpatwari/GitNexus · error · SandboxError
sandbox_copy must be a repository-relative path: {raw!r}
Error message
sandbox_copy must be a repository-relative path: {raw!r} What it means
Raised by _sandbox_copy_declarations for each declared path string that is absolute (starts with '/'), has no parts (empty after PurePosixPath parsing), or contains a '..' component anywhere in its parts. The harness only accepts repository-relative paths that stay within the repo root — this is both a path-traversal security guard and a determinism guard (absolute or escaping paths would capture bytes outside the declared repo identity).
Source
Thrown at eval/workflow_bench/task_assets.py:551
self._record_directory(relative)
def finished_entries(self) -> tuple[AssetManifestEntry, ...]:
return tuple(sorted(self.entries.values(), key=lambda entry: entry.path.as_posix()))
def _sandbox_copy_declarations(
task: Mapping[str, Any],
) -> tuple[tuple[str, ...], tuple[PurePosixPath, ...]]:
raw_declarations = task.get("sandbox_copy", [])
if not isinstance(raw_declarations, list) or not all(isinstance(item, str) and item for item in raw_declarations):
raise SandboxError("sandbox_copy must be a list of nonblank repository-relative paths")
declarations = tuple(raw_declarations)
paths: list[PurePosixPath] = []
for raw in declarations:
relative = PurePosixPath(raw)
if relative.is_absolute() or not relative.parts or ".." in relative.parts:
raise SandboxError(f"sandbox_copy must be a repository-relative path: {raw!r}")
_validate_manifest_path(relative)
paths.append(relative)
for index, path in enumerate(paths):
for other in paths[index + 1 :]:
if path == other or path in other.parents or other in path.parents:
raise SandboxError(f"sandbox_copy declarations overlap: {path} and {other}")
return declarations, tuple(paths)
def _sandbox_dependency_declarations(
task: Mapping[str, Any],
) -> tuple[_DependencyDeclaration, ...]:
raw_declarations = task.get("sandbox_dependencies", [])
if not isinstance(raw_declarations, list):
raise SandboxError("sandbox_dependencies must be a list")
declarations: list[_DependencyDeclaration] = []
for item in raw_declarations:
if (View on GitHub (pinned to d540b00184)
Solutions
- Rewrite each sandbox_copy entry as a clean repo-relative path with no '..': `src/lib`, `tests/fixtures`, not `/home/user/repo/src` or `../shared/lib`.
- Normalize at authoring time with `os.path.relpath(path, repo_root)` and reject results starting with '..'.
- Validate with the provided path guard before calling prepare() (see typeGuard).
- If a path outside the repo is genuinely needed, copy it into the repo first or declare it as a sandbox_dependency with a proper source.
Example fix
// before
{"sandbox_copy": ["/home/user/repo/src", "../shared/include"]}
// after
{"sandbox_copy": ["src", "include"]} Defensive patterns
Strategy: type-guard
Validate before calling
from pathlib import PurePosixPath
def validate_copy_paths_relative(task: dict) -> None:
for raw in task.get("sandbox_copy", []):
p = PurePosixPath(raw)
if p.is_absolute() or not p.parts or ".." in p.parts:
raise ValueError(f"sandbox_copy must be repository-relative, got {raw!r}")
validate_copy_paths_relative(task) Type guard
from pathlib import PurePosixPath
def is_repo_relative_bounded(raw: str) -> bool:
p = PurePosixPath(raw)
return not p.is_absolute() and bool(p.parts) and ".." not in p.parts 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 "repository-relative path" in str(exc):
# rewrite the offending path to a clean repo-relative form
raise
raise Prevention
- Author paths relative to the repo root with no '..' components.
- Normalize with os.path.relpath(path, repo_root) and reject results starting with '..'.
- Never paste absolute paths from outside the repo into sandbox_copy.
When it happens
Trigger: A declaration like `/abs/path`, `../sibling`, `repo/../outside`, `./` (no parts), or `''` that produced an empty PurePosixPath. Also a Windows-style path with a drive letter parsed unexpectedly. The check is per-element: `relative.is_absolute() or not relative.parts or '..' in relative.parts`.
Common situations: Author copies an absolute path from an IDE. Relative path that walks up with `..`. A templating bug that prefixes '/'. A path normalization step that collapses `a/../..` to an escape.
Related errors
- dependency source must stay inside the repository: {source_p
- dependency target must stay inside the clone: {target_path}
- {label} contains an unsafe path component: {relative}
- unsafe results artifact path: {relative_value!r}
- extra read-only mount target must be absolute: {mount.target
AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12).
Data as JSON: /api/errors/4702f1a8471fee6f.
Report an issue: GitHub.