abhigyanpatwari/GitNexus · critical · RuntimeError
clone unexpectedly has an external object alternate: {altern
Error message
clone unexpectedly has an external object alternate: {alternates} What it means
Thrown by make_worktree after a `git clone --no-local --no-hardlinks`. That clone mode is chosen so the benchmark arm gets a fully self-contained object database; if `.git/objects/info/alternates` exists afterward, the clone is secretly borrowing objects from another store, which breaks the isolation guarantee (the arm could read or depend on host state it should not see).
Source
Thrown at eval/workflow_bench/runner_artifacts.py:321
target = Path(tempfile.mkdtemp(prefix="wfbench-", dir=parent))
target.rmdir()
try:
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}")
raiseView on GitHub (pinned to d540b00184)
Solutions
- Pass `-c clone.defaultResolverName=loose` (or unset any alternates-inducing config) for the clone, or clone from a clean pack of the repo.
- Check `git config --system --list` and `--global --list` for object-sharing settings and remove them for the benchmark run.
- Re-create the source repo as a normal full clone with no alternates before benchmarking.
- Run the harness in the clean container/sandbox image it ships with, where this config is controlled.
Example fix
// before run_checked(['git','clone','--no-local','--no-hardlinks', str(repo), str(target)]) // after — disable any inherited alternates behavior run_checked(['git','-c','protocol.version=2','clone','--no-local','--no-hardlinks','--no-tags','--quiet', str(repo), str(target)]) # plus ensure source `repo` has no .git/objects/info/alternates of its own
Defensive patterns
Strategy: validation
Validate before calling
from pathlib import Path
def clone_has_no_alternates(target: Path) -> bool:
return not (target / '.git' / 'objects' / 'info' / 'alternates').exists() Type guard
null
Try / catch
try:
make_worktree(repo, ref, parent)
except RuntimeError as e:
if 'external object alternate' in str(e):
# inspect/fix git config that induced alternates, then retry
raise
raise Prevention
- Run the harness in its clean container image where git config is controlled.
- Check `git config --system --global --list` for object-sharing keys before benchmarking.
- Ensure the source repo has no .git/objects/info/alternates of its own.
- Prefer cloning from a freshly made full pack of the repo.
When it happens
Trigger: After clone, `(target/.git/objects/info/alternates).exists()` is True. The clone picked up an alternates file, e.g. because a global git config or template enabled it, or the source repo itself had alternates.
Common situations: A global ~/.gitconfig or /etc/gitconfig sets clone.defaultResolverName or shares objects; the source repo is itself a linked/alternate checkout; a CI image pre-configures object sharing; running against a repo created by `git clone --reference`.
Related errors
- clone object is hardlinked to host storage: {obj}
- ref {ref!r} not found in clone of {repo}
- generated artifact is not a regular non-symlink file: {path}
- generated artifact changed type while opening: {path}
- GitNexus MCP executable must stay outside {SANDBOX_WORKSPACE
AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12).
Data as JSON: /api/errors/932dd114af16f6a9.
Report an issue: GitHub.