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

  1. Pass worktree.expanduser().resolve() (or an already-resolved real directory) into staged_task_oracle.
  2. Ensure the worktree directory exists and is created by the caller (e.g. git clone / mkdir) before invocation.
  3. On macOS avoid /tmp literally — use /private/tmp or a path under the project dir, or resolve() first.
  4. 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

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


AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12). Data as JSON: /api/errors/cb4a4dee9f0a3ac1. Report an issue: GitHub.