abhigyanpatwari/GitNexus · error · SandboxError
Compound Engineering plugin component is unreadable: {direct
Error message
Compound Engineering plugin component is unreadable: {directory}: {exc} What it means
For each name in _ALLOWED_PLUGIN_DIRS (skills, scripts, assets) that exists, the harness lstat's it before walking. OSError on that lstat (other than non-existence, which is skipped) raises this error rather than silently treating the component as missing.
Source
Thrown at eval/workflow_bench/runtime_mounts.py:342
except OSError as exc:
raise SandboxError(f"Compound Engineering plugin entry is unreadable: {entry.path}: {exc}") from exc
if stat.S_ISLNK(metadata.st_mode):
raise SandboxError(f"Compound Engineering plugin entries must not be symlinks: {entry.path}")
if stat.S_ISDIR(metadata.st_mode):
yield from walk(Path(entry.path), relative)
elif stat.S_ISREG(metadata.st_mode):
yield relative, Path(entry.path)
else:
raise SandboxError(f"Compound Engineering plugin entries must be regular files: {entry.path}")
for name in _ALLOWED_PLUGIN_DIRS:
directory = source / name
if not directory.exists():
continue
try:
metadata = directory.lstat()
except OSError as exc:
raise SandboxError(f"Compound Engineering plugin component is unreadable: {directory}: {exc}") from exc
if stat.S_ISLNK(metadata.st_mode) or not stat.S_ISDIR(metadata.st_mode):
raise SandboxError(f"Compound Engineering plugin component must be a real directory: {directory}")
yield from walk(directory, PurePosixPath(name))
def _bounded_plugin_bytes(path: Path) -> tuple[bytes, bool]:
"""Read one stable regular file without following a last-component symlink."""
try:
before = path.lstat()
except OSError as exc:
raise SandboxError(f"Compound Engineering plugin file is unreadable: {path}: {exc}") from exc
if stat.S_ISLNK(before.st_mode) or not stat.S_ISREG(before.st_mode):
raise SandboxError(f"Compound Engineering plugin file must be regular and non-symlink: {path}")
if before.st_size > MAX_CE_PLUGIN_FILE_BYTES:
raise SandboxError(f"Compound Engineering plugin file exceeds the per-file limit: {path}")
descriptor = os.open(path, os.O_RDONLY | getattr(os, "O_NOFOLLOW", 0))
try:View on GitHub (pinned to d540b00184)
Solutions
- Grant read+execute on each component: `chmod +rX <plugin_dir>/skills <plugin_dir>/scripts <plugin_dir>/assets`.
- Move the plugin to a stable local filesystem and re-run.
- Re-extract from a clean tarball.
Defensive patterns
Strategy: validation
Validate before calling
from pathlib import Path
def components_lstatable(source: Path) -> bool:
for name in ("skills", "scripts", "assets"):
d = source / name
if not d.exists():
continue
try:
d.lstat()
except OSError:
return False
return True Try / catch
try:
list(_plugin_files(source))
except SandboxError as exc:
if "component is unreadable" in str(exc):
# chmod +rX the named component directory
...
raise Prevention
- Apply `chmod -R +rX` to the plugin source before benchmarking.
- Keep plugins on a stable local filesystem rather than a flaky network mount.
When it happens
Trigger: skills/ (or scripts/, assets/) exists per .exists() but lstat fails — typically a transient I/O error, broken NFS handle, or permission boundary at the directory itself.
Common situations: Restrictive ACL on a single component directory; container filesystem hiccup; lazy-unmount race.
Related errors
- Compound Engineering plugin directory is unreadable: {direct
- Compound Engineering plugin entry is unreadable: {entry.path
- Compound Engineering plugin file is unreadable: {path}: {exc
- Could not read ${GITNEXUS_RC_FILENAME}: ${(err as Error).mes
- candidate destination is unreadable: {relative}: {exc}
AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12).
Data as JSON: /api/errors/da15bdc1f262b8de.
Report an issue: GitHub.