abhigyanpatwari/GitNexus · error · ValueError

candidate destination parent must be a real directory: {rela

Error message

candidate destination parent must be a real directory: {relative.parent}: {exc}

What it means

Thrown by _replace_regular_file (evolution.py:183) while walking the intermediate parent components of the destination with directory file descriptors using O_RDONLY|O_DIRECTORY|O_NOFOLLOW. Each parent part is mkdir'd (0o700, FileExistsError ignored) then re-opened; if os.open of a part fails with any OSError, the parent is not a real directory — it is a symlink, a regular file, or unreadable.

Source

Thrown at eval/workflow_bench/evolution.py:183

def _replace_regular_file(root: Path, relative: Path, content: bytes) -> None:
    """Replace a clone file through validated directory descriptors."""

    if relative.is_absolute() or not relative.parts or ".." in relative.parts:
        raise ValueError(f"candidate destination escapes the clone: {relative}")
    _require_real_directory(root, label="candidate destination root")
    directory_flags = os.O_RDONLY | getattr(os, "O_DIRECTORY", 0) | getattr(os, "O_NOFOLLOW", 0)
    descriptor = os.open(root, directory_flags)
    try:
        for part in relative.parts[:-1]:
            try:
                os.mkdir(part, mode=0o700, dir_fd=descriptor)
            except FileExistsError:
                pass
            try:
                child = os.open(part, directory_flags, dir_fd=descriptor)
            except OSError as exc:
                raise ValueError(
                    f"candidate destination parent must be a real directory: {relative.parent}: {exc}"
                ) from exc
            os.close(descriptor)
            descriptor = child

        leaf = relative.name
        try:
            existing = os.stat(leaf, dir_fd=descriptor, follow_symlinks=False)
        except FileNotFoundError:
            existing = None
        except OSError as exc:
            raise ValueError(f"candidate destination is unreadable: {relative}: {exc}") from exc
        if existing is not None and (stat.S_ISLNK(existing.st_mode) or not stat.S_ISREG(existing.st_mode)):
            raise ValueError(f"candidate destination must be a regular non-symlink file: {relative}")

        temporary = f".wfbench-overlay-{secrets.token_hex(12)}"
        temp_descriptor = os.open(
            temporary,

View on GitHub (pinned to d540b00184)

Solutions

  1. Inspect the clone at the named {relative.parent}: remove any symlink/file blocking the directory chain.
  2. Ensure the clone root and .claude/skills path are writable so missing parents can be created (mode 0o700).
  3. Reset the clone to a clean checkout and re-apply the overlay.

Example fix

# before: a file blocks the directory chain in the clone
clone/.claude   # is a regular file, not a dir -> parent not a real directory

# after: ensure real directories exist
from pathlib import Path
for d in [Path('clone/.claude'), Path('clone/.claude/skills')]:
    if d.exists() and not d.is_dir():
        d.unlink()
    d.mkdir(parents=True, exist_ok=True)
Defensive patterns

Strategy: validation

Validate before calling

import os, stat
from pathlib import Path

def clone_parents_are_real_dirs(clone: Path, rel: Path) -> bool:
    cur = clone
    for part in rel.parts[:-1]:
        cur = cur / part
        try:
            m = cur.lstat().st_mode
        except FileNotFoundError:
            continue
        if stat.S_ISLNK(m) or not stat.S_ISDIR(m):
            return False
    return True

Type guard

null

Try / catch

try:
    apply_candidate_overlay(overlay, worktree, sandbox=sandbox)
except ValueError as exc:
    if 'parent must be a real directory' in str(exc):
        # inspect and repair the named parent path in the clone
        ...

Prevention

When it happens

Trigger: An intermediate path component in the clone is a symlink or regular file instead of a directory (e.g. .claude is a file); the clone lacks write permission to mkdir the missing parent; an existing parent has mode bits that block open.

Common situations: The clone already contains a file named '.claude' or 'skills' where a directory is expected; clone was partially reset or left in a broken state; running as a user without write permission on the clone root.

Related errors


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