gastownhall/beads · error
failed to pin target git directory identity: %w
Error message
failed to pin target git directory identity: %w
What it means
inspectWorktreeTarget Lstats the resolved git directory (--absolute-git-dir) to pin its identity. If that Lstat fails, this wrapped error is returned. Git resolved the gitdir path moments earlier, so the directory has disappeared or become unreadable — indicating drift, corruption, or a concurrent prune.
Source
Thrown at cmd/bd/worktree_cmd.go:1013
headOID := strings.TrimSpace(string(headOutput))
if headOID == "" || headOID != worktree.headOID {
return pinnedWorktreeTarget{}, fmt.Errorf(
"target HEAD disagrees with git worktree registry (registry %q, target %q)",
worktree.headOID,
headOID,
)
}
pathInfo, err := os.Lstat(worktree.path)
if err != nil {
return pinnedWorktreeTarget{}, fmt.Errorf("failed to pin target directory identity: %w", err)
}
if pathInfo.Mode()&os.ModeSymlink != 0 || !pathInfo.IsDir() {
return pinnedWorktreeTarget{}, fmt.Errorf("target path is not a real directory: %s", worktree.path)
}
gitDirInfo, err := os.Lstat(gitDir)
if err != nil {
return pinnedWorktreeTarget{}, fmt.Errorf("failed to pin target git directory identity: %w", err)
}
if gitDirInfo.Mode()&os.ModeSymlink != 0 || !gitDirInfo.IsDir() {
return pinnedWorktreeTarget{}, fmt.Errorf("target git directory is not a real directory: %s", gitDir)
}
gitMarkerPath := filepath.Join(worktree.path, ".git")
gitMarkerInfo, err := os.Lstat(gitMarkerPath)
if err != nil {
return pinnedWorktreeTarget{}, fmt.Errorf("failed to pin target git marker identity: %w", err)
}
if gitMarkerInfo.Mode()&os.ModeSymlink != 0 || !gitMarkerInfo.Mode().IsRegular() {
return pinnedWorktreeTarget{}, fmt.Errorf("target git marker is not a regular file: %s", gitMarkerPath)
}
gitDirFingerprint, err := fingerprintWorktreeFilesystem(gitDir)
if err != nil {
return pinnedWorktreeTarget{}, fmt.Errorf("failed to fingerprint target git directory: %w", err)
}
gitMarkerFingerprint, err := fingerprintWorktreeFilesystem(gitMarkerPath)
if err != nil {View on GitHub (pinned to 71377f2769)
Solutions
- Check the wrapped Lstat error; verify the gitdir referenced by the worktree's .git file exists and is readable.
- Re-run the command — a transient race either succeeds or fails deterministically (as not-found) on retry.
- Run `git worktree prune` to clean dangling gitdir entries, then re-register the worktree if it should exist.
- Ensure no concurrent cleanup processes touch .git/worktrees during removal.
Example fix
// before bd worktree remove feature-x // error: failed to pin target git directory identity: lstat /repo/.git/worktrees/feature-x: no such file or directory // after git worktree prune bd worktree list # stale entry pruned; nothing to remove
Defensive patterns
Strategy: retry
Validate before calling
import { readFileSync, existsSync, lstatSync } from "node:fs";
const gitdir = readFileSync(`${worktreePath}/.git`, "utf8").trim().replace(/^gitdir:\s*/, "");
if (!existsSync(gitdir) || !lstatSync(gitdir).isDirectory()) {
throw new Error("worktree gitdir dangling — run git worktree prune");
} Try / catch
try {
await bd("worktree", "remove", path);
} catch (e) {
if (String(e.message).includes("failed to pin target git directory identity")) {
execSync("git worktree prune");
} else throw e;
} Prevention
- Serialize removal/prune operations — never run concurrent prunes.
- Exclude .git/worktrees from external cleanup/backup tooling.
- Re-run after transient races; failures are deterministic on retry.
- Verify the gitdir referenced by the worktree's .git file exists before removal.
When it happens
Trigger: The worktree's gitdir (usually under the main repo's .git/worktrees/<name>) was deleted between the rev-parse and the Lstat; permissions changed; the main repo .git moved mid-operation; revalidation racing with `git worktree prune` or another removal.
Common situations: Two concurrent `bd worktree remove` or prune operations racing on the same repo; a cleanup script removing stale .git/worktrees entries; antivirus/backup tools temporarily locking or moving directories; network filesystem flakiness.
Related errors
- target HEAD disagrees with git worktree registry (registry %
- failed to pin target directory identity: %w
- target is no longer registered at %s
- registered target identity changed
- target git directory changed
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/7a0ab672d8b2ebaf.
Report an issue: GitHub.