abhigyanpatwari/GitNexus · error · ValueError
oracle worktree must be a real non-symlink directory: {root}
Error message
oracle worktree must be a real non-symlink directory: {root} What it means
Entry guard of the staged_task_oracle context manager: the user-supplied worktree must exist, be a real (non-symlink) directory, and resolve(strict=True) to itself (no symlink in any path component). This is a precondition failure before any staging begins, so it is caller-fixable rather than evidence of tampering.
Source
Thrown at eval/workflow_bench/oracle_assets.py:514
current = stage_root
for part in relative.parts[:-1]:
current /= part
metadata = current.lstat()
if stat.S_ISLNK(metadata.st_mode) or not stat.S_ISDIR(metadata.st_mode):
raise ValueError(f"oracle stage parent changed during verification: {item.target}")
observed = _read_oracle_file(stage_root, relative)
if observed != item.payload:
raise ValueError(f"oracle file changed during verification: {item.target}")
@contextmanager
def staged_task_oracle(worktree: Path, snapshot: TaskOracleSnapshot) -> Iterator[Path]:
"""Materialize a private random oracle root only after the model exits."""
root = worktree.expanduser().absolute()
metadata = root.lstat()
if stat.S_ISLNK(metadata.st_mode) or not stat.S_ISDIR(metadata.st_mode) or root.resolve(strict=True) != root:
raise ValueError(f"oracle worktree must be a real non-symlink directory: {root}")
stage_root = root / f".wfbench-oracle-{secrets.token_hex(16)}"
stage_root.mkdir(mode=0o700)
stage_root.chmod(0o700)
primary: BaseException | None = None
try:
for item in snapshot.files:
_write_stage_file(stage_root, item)
yield stage_root
_verify_staged_oracle(stage_root, snapshot)
except BaseException as exc:
primary = exc
raise
finally:
try:
mode = stage_root.lstat().st_mode
if stat.S_ISLNK(mode):
stage_root.unlink()
elif stat.S_ISDIR(mode):View on GitHub (pinned to d540b00184)
Solutions
- Pass worktree.expanduser().resolve() (or an already-resolved real directory) into staged_task_oracle.
- Ensure the worktree directory exists and is created by the caller (e.g. git clone / mkdir) before invocation.
- On macOS avoid /tmp literally — use /private/tmp or a path under the project dir, or resolve() first.
- Verify with `Path(p).is_dir() and not Path(p).is_symlink()` before the call.
Example fix
// before
with staged_task_oracle(Path('/tmp/wfbench'), snap) as r: ...
// after
root = Path('/tmp/wfbench').expanduser().resolve()
assert root.is_dir() and not root.is_symlink()
with staged_task_oracle(root, snap) as r: ... Defensive patterns
Strategy: validation
Validate before calling
import stat
from pathlib import Path
def resolve_worktree(p: str | Path) -> Path:
root = Path(p).expanduser().absolute()
meta = root.lstat()
if stat.S_ISLNK(meta.st_mode) or not stat.S_ISDIR(meta.st_mode):
raise ValueError(f'{root} must be a real non-symlink directory')
if root.resolve(strict=True) != root:
raise ValueError(f'{root} contains a symlink component; use {root.resolve()}')
return root
# then: with staged_task_oracle(resolve_worktree(path), snapshot) as r: ... Type guard
from pathlib import Path
import stat
def is_real_directory(p: str | Path) -> bool:
path = Path(p)
try:
meta = path.lstat()
except (FileNotFoundError, NotADirectoryError):
return False
return stat.S_ISDIR(meta.st_mode) and not stat.S_ISLNK(meta.st_mode) and path.resolve(strict=True) == path Try / catch
try:
with staged_task_oracle(worktree, snapshot) as stage:
...
except ValueError as exc:
if 'must be a real non-symlink directory' in str(exc):
worktree = Path(worktree).resolve()
# retry once with the resolved path Prevention
- Always pass `Path(worktree).expanduser().resolve()` rather than raw input.
- On macOS avoid /tmp — use /private/tmp or a path under the project.
- Reject user-supplied paths that contain symlinks at the config boundary.
When it happens
Trigger: Raised immediately when staged_task_oracle(worktree, snapshot) is called and worktree is missing, is a regular file, is a symlink, or contains a symlink in its path components (root.resolve(strict=True) != root).
Common situations: Passing a path that is a symlink to the real worktree (common in CI with workspace shortcuts); pointing at the worktree before cloning; passing the repository root file itself; Mac /tmp is a symlink to /private/tmp — `Path('/tmp/x')` resolves to `/private/tmp/x`.
Related errors
- {label} must be a real non-symlink directory: {path}
- {label} must be a regular non-symlink file: {path}
- skill fingerprint input must be a regular non-symlink file:
- promotion binding is missing hidden-oracle or dependency dig
- promotion binding is missing hidden-oracle files
AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12).
Data as JSON: /api/errors/cb4a4dee9f0a3ac1.
Report an issue: GitHub.