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

  1. Check the wrapped Lstat error; verify the gitdir referenced by the worktree's .git file exists and is readable.
  2. Re-run the command — a transient race either succeeds or fails deterministically (as not-found) on retry.
  3. Run `git worktree prune` to clean dangling gitdir entries, then re-register the worktree if it should exist.
  4. 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

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


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/7a0ab672d8b2ebaf. Report an issue: GitHub.