abhigyanpatwari/GitNexus · critical · RuntimeError

clone object is hardlinked to host storage: {obj}

Error message

clone object is hardlinked to host storage: {obj}

What it means

Thrown by make_worktree during its post-clone isolation audit. Even with --no-hardlinks, the harness walks every file under target/.git/objects and rejects any with a link count (st_nlink) greater than 1, because a hardlinked object means the arm shares physical storage with the host and a mutation in one affects the other.

Source

Thrown at eval/workflow_bench/runner_artifacts.py:324

        run_checked(
            [
                "git",
                "clone",
                "--no-local",
                "--no-hardlinks",
                "--no-tags",
                "--quiet",
                str(repo),
                str(target),
            ],
            timeout=600,
        )
        alternates = target / ".git" / "objects" / "info" / "alternates"
        if alternates.exists():
            raise RuntimeError(f"clone unexpectedly has an external object alternate: {alternates}")
        for obj in (target / ".git" / "objects").rglob("*"):
            if obj.is_file() and obj.stat().st_nlink > 1:
                raise RuntimeError(f"clone object is hardlinked to host storage: {obj}")
        for candidate in (ref, f"origin/{ref}"):
            proc = run_managed(
                ["git", "-C", str(target), "checkout", "--detach", "--quiet", candidate],
                timeout=60,
            )
            if proc.ok:
                return target
        raise RuntimeError(f"ref {ref!r} not found in clone of {repo}")
    except BaseException as primary:
        if target.exists():
            try:
                shutil.rmtree(target)
            except OSError as cleanup:
                primary.add_note(f"clone cleanup also failed: {type(cleanup).__name__}: {cleanup}")
        raise


def remove_clone(clone: Path) -> None:

View on GitHub (pinned to d540b00184)

Solutions

  1. Ensure source repo and target live on different filesystems/devices so hardlinking is impossible, or rely on the --no-local transport the harness already requests.
  2. Do not copy or rsync the resulting clone with hard-link options.
  3. Use the harness's own make_worktree rather than a manual clone, since it already passes --no-local --no-hardlinks.
  4. Upgrade git; older versions had bugs where --no-hardlinks was not honored in all paths.

Example fix

// before — manual clone that may hardlink
subprocess.run(['git','clone', str(repo), str(target)])  # same-volume -> hardlinks

// after — use the harness helper which forces --no-local --no-hardlinks
from eval.workflow_bench.runner_artifacts import make_worktree
target = make_worktree(repo, ref, parent=tempfile.gettempdir())
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path

def no_hardlinked_objects(target: Path) -> bool:
    objects = target / '.git' / 'objects'
    return all(f.stat().st_nlink == 1 for f in objects.rglob('*') if f.is_file())

Type guard

null

Try / catch

try:
    make_worktree(repo, ref, parent)
except RuntimeError as e:
    if 'hardlinked to host storage' in str(e):
        # move source/target to different filesystems, or stop copying with -l
        raise
    raise

Prevention

When it happens

Trigger: For some object file `obj` under target/.git/objects, `obj.stat().st_nlink > 1`. A file there is hardlinked to a file outside the clone (or to another clone's object).

Common situations: A filesystem or git version that ignores --no-hardlinks; copying the worktree with `cp -l`/rsync --link-dest; a host with link-based dedup; the source repo and target on the same volume such that git fell back to hardlinks despite the flag.

Related errors


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