abhigyanpatwari/GitNexus · error · SandboxError
sandbox_copy path is not valid UTF-8: {relative!s}
Error message
sandbox_copy path is not valid UTF-8: {relative!s} What it means
Raised by _validate_manifest_path when relative.as_posix().encode('utf-8') throws UnicodeEncodeError. sandbox_copy paths must round-trip cleanly through UTF-8 so the manifest JSON and digests stay deterministic; any path that cannot be UTF-8 encoded (e.g. containing surrogateescape codepoints from os.listdir on Linux) is rejected before it enters the manifest.
Source
Thrown at eval/workflow_bench/task_assets.py:892
view = view[written:]
def _mutation_identity(metadata: os.stat_result) -> tuple[int, int, int, int, int, int]:
return (
metadata.st_dev,
metadata.st_ino,
metadata.st_mode,
metadata.st_size,
metadata.st_mtime_ns,
metadata.st_ctime_ns,
)
def _validate_manifest_path(relative: PurePosixPath) -> None:
try:
path_bytes = len(relative.as_posix().encode("utf-8"))
except UnicodeEncodeError as exc:
raise SandboxError(f"sandbox_copy path is not valid UTF-8: {relative!s}") from exc
if path_bytes > MAX_TASK_ASSET_PATH_BYTES:
raise SandboxError("sandbox_copy exceeds the path byte limit")
def _manifest_digest(entries: tuple[AssetManifestEntry, ...]) -> str:
payload = [
{
"kind": entry.kind,
"link_target": entry.link_target,
"mode": entry.mode,
"path": entry.path.as_posix(),
"sha256": entry.sha256,
"size": entry.size,
}
for entry in entries
]
return hashlib.sha256(json.dumps(payload, sort_keys=True, separators=(",", ":")).encode()).hexdigest()
View on GitHub (pinned to d540b00184)
Solutions
- Normalize the sandbox_copy path to a clean str before building the declaration: decode bytes with the actual filesystem encoding and re-encode strict utf-8, replacing or rejecting non-decodable names.
- Rename the offending source file on disk to a valid UTF-8 name so the declaration path is clean.
- If you genuinely need non-UTF-8 paths, they are unsupported by this module — exclude them from sandbox_copy or pre-process them into UTF-8 equivalents.
Example fix
# before: raw bytes path leaks surrogates into the declaration
raw = os.fsdecode(os.listdir(b'/repo')[0]) # may contain surrogates
source = PurePosixPath(raw)
# after: enforce clean UTF-8 at the boundary
raw = os.listdir('/repo')[0]
source = PurePosixPath(raw)
assert source.as_posix().encode('utf-8') # fails fast on bad input Defensive patterns
Strategy: validation
Validate before calling
from pathlib import PurePosixPath
def assert_utf8_path(relative: PurePosixPath) -> None:
posix = relative.as_posix()
try:
posix.encode('utf-8')
except UnicodeEncodeError:
raise ValueError(f'sandbox_copy path is not valid UTF-8: {posix!r}') from None
# Run on every declared source/target before building the task dict. Type guard
from pathlib import PurePosixPath
def is_utf8_path(relative: PurePosixPath) -> bool:
try:
relative.as_posix().encode('utf-8')
return True
except UnicodeEncodeError:
return False Try / catch
from .proposer_sandbox import SandboxError
task_paths = [PurePosixPath(d['source']) for d in task.get('sandbox_copy', [])]
if not all(is_utf8_path(p) for p in task_paths):
# sanitize / rename offending files before capture instead of catching post-hoc
task['sandbox_copy'] = [d for d in task['sandbox_copy'] if is_utf8_path(PurePosixPath(d['source']))]
try:
stage_task_assets(task, ...)
except SandboxError as exc:
if 'not valid UTF-8' in str(exc):
# rename the offending source file to clean UTF-8, then retry prepare
...
raise Prevention
- Build all sandbox_copy paths from clean str, never from surrogateescape-decoded bytes.
- Reject or rename non-UTF-8 filenames at the repo boundary, before they reach sandbox_copy declarations.
- Run assert_utf8_path over declared paths in task-validation, upstream of the asset module.
When it happens
Trigger: A sandbox_copy declaration whose source/target path was constructed from raw os.scandir/os.listdir bytes decoded with surrogateescape, or assembled from a bytes path that included invalid UTF-8 sequences, then passed through PurePosixPath. The surrogate codepoints (U+DC80..U+DCFF) survive into PurePosixPath but fail .encode('utf-8').
Common situations: Mixing bytes-based path handling with str PurePosixPath; copying assets from a filesystem with legacy non-UTF-8 filenames (Latin-1,Shift-JIS); test fixtures that build paths from arbitrary bytes; cross-platform path joining that injects lone surrogates.
Related errors
- sandbox_copy paths collide at {current}
- sandbox_copy exceeds the path byte limit
- {label} is unavailable: {path}: {exc}
- {label} must be a real non-symlink directory: {path}
- {label} contains an unsafe path component: {relative}
AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12).
Data as JSON: /api/errors/8cf957adc1258c30.
Report an issue: GitHub.