{"record":{"id":"7a0ab672d8b2ebaf","repo":"gastownhall/beads","slug":"failed-to-pin-target-git-directory-identity-w","errorCode":null,"errorMessage":"failed to pin target git directory identity: %w","messagePattern":"failed to pin target git directory identity: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/bd/worktree_cmd.go","lineNumber":1013,"sourceCode":"\n\theadOID := strings.TrimSpace(string(headOutput))\n\tif headOID == \"\" || headOID != worktree.headOID {\n\t\treturn pinnedWorktreeTarget{}, fmt.Errorf(\n\t\t\t\"target HEAD disagrees with git worktree registry (registry %q, target %q)\",\n\t\t\tworktree.headOID,\n\t\t\theadOID,\n\t\t)\n\t}\n\tpathInfo, err := os.Lstat(worktree.path)\n\tif err != nil {\n\t\treturn pinnedWorktreeTarget{}, fmt.Errorf(\"failed to pin target directory identity: %w\", err)\n\t}\n\tif pathInfo.Mode()&os.ModeSymlink != 0 || !pathInfo.IsDir() {\n\t\treturn pinnedWorktreeTarget{}, fmt.Errorf(\"target path is not a real directory: %s\", worktree.path)\n\t}\n\tgitDirInfo, err := os.Lstat(gitDir)\n\tif err != nil {\n\t\treturn pinnedWorktreeTarget{}, fmt.Errorf(\"failed to pin target git directory identity: %w\", err)\n\t}\n\tif gitDirInfo.Mode()&os.ModeSymlink != 0 || !gitDirInfo.IsDir() {\n\t\treturn pinnedWorktreeTarget{}, fmt.Errorf(\"target git directory is not a real directory: %s\", gitDir)\n\t}\n\tgitMarkerPath := filepath.Join(worktree.path, \".git\")\n\tgitMarkerInfo, err := os.Lstat(gitMarkerPath)\n\tif err != nil {\n\t\treturn pinnedWorktreeTarget{}, fmt.Errorf(\"failed to pin target git marker identity: %w\", err)\n\t}\n\tif gitMarkerInfo.Mode()&os.ModeSymlink != 0 || !gitMarkerInfo.Mode().IsRegular() {\n\t\treturn pinnedWorktreeTarget{}, fmt.Errorf(\"target git marker is not a regular file: %s\", gitMarkerPath)\n\t}\n\tgitDirFingerprint, err := fingerprintWorktreeFilesystem(gitDir)\n\tif err != nil {\n\t\treturn pinnedWorktreeTarget{}, fmt.Errorf(\"failed to fingerprint target git directory: %w\", err)\n\t}\n\tgitMarkerFingerprint, err := fingerprintWorktreeFilesystem(gitMarkerPath)\n\tif err != nil {","sourceCodeStart":995,"sourceCodeEnd":1031,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/worktree_cmd.go#L995-L1031","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nbd worktree remove feature-x\n// error: failed to pin target git directory identity: lstat /repo/.git/worktrees/feature-x: no such file or directory\n// after\ngit worktree prune\nbd worktree list   # stale entry pruned; nothing to remove","handlingStrategy":"retry","validationCode":"import { readFileSync, existsSync, lstatSync } from \"node:fs\";\nconst gitdir = readFileSync(`${worktreePath}/.git`, \"utf8\").trim().replace(/^gitdir:\\s*/, \"\");\nif (!existsSync(gitdir) || !lstatSync(gitdir).isDirectory()) {\n  throw new Error(\"worktree gitdir dangling — run git worktree prune\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  await bd(\"worktree\", \"remove\", path);\n} catch (e) {\n  if (String(e.message).includes(\"failed to pin target git directory identity\")) {\n    execSync(\"git worktree prune\");\n  } else throw e;\n}","preventionTips":["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."],"tags":["worktree","gitdir","lstat","race-condition"],"backgroundTag":"broken-git-worktree","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}