gastownhall/beads · error
target git directory is not a real directory: %s
Error message
target git directory is not a real directory: %s
What it means
Before removing a worktree, bd pins the filesystem identity of the target's git directory (the worktree's private .git dir under .git/worktrees/). This error means `os.Lstat` on that directory succeeded, but it is a symlink or not a directory. bd refuses to fingerprint/remove a target whose gitdir is not a plain directory, because identity pinning and hashing would be unreliable.
Source
Thrown at cmd/bd/worktree_cmd.go:1016
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 {
return pinnedWorktreeTarget{}, fmt.Errorf("failed to fingerprint target git marker: %w", err)
}
statusFingerprint, err := fingerprintWorktreeStatusPaths(worktree.path, string(statusOutput))View on GitHub (pinned to 71377f2769)
Solutions
- Inspect the path in the error with `ls -la`; if it is a symlink, replace it with a real directory or recreate the worktree
- Run `git worktree list` and `git worktree prune`, then re-add the worktree with `git worktree add`
- If the gitdir was replaced by a file, remove and re-create the worktree cleanly instead of editing internals
Example fix
// before: manual symlinked gitdir ln -s /elsewhere/wt.git /repo/.git/worktrees/mywt // after: let git manage it git worktree remove --force mywt && git worktree add ../mywt -b mybranch
Defensive patterns
Strategy: validation
Validate before calling
info, err := os.Lstat(gitDir)
if err != nil || info.Mode()&os.ModeSymlink != 0 || !info.IsDir() {
return fmt.Errorf("refusing: gitdir %s is not a real directory", gitDir)
} Type guard
func isRealDir(path string) bool {
info, err := os.Lstat(path)
return err == nil && info.Mode()&os.ModeSymlink == 0 && info.IsDir()
} Prevention
- Never hand-edit .git/worktrees/<name>/ metadata; use git worktree add/remove/repair
- Check `git worktree list` before scripted removals
- Avoid symlinking worktree gitdirs across filesystems
When it happens
Trigger: Running `bd worktree remove` (prepareWorktreeRemoval) or a revalidation (observeRevalidation) when the resolved gitdir path is a symlink, was replaced by a file, or the worktree registry points at a stale/corrupted gitdir path.
Common situations: Moving the repository with symlinks in .git/worktrees; manual edits to .git/worktrees/<name>/gitdir; restoring a repo from backup that turned gitdirs into symlinks; tools that rewrite worktree metadata.
Related errors
- failed to pin target git marker identity: %w
- cannot safely prepare .gitignore cleanup: %w
- target directory identity changed
- target git directory identity changed
- target git marker identity changed
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/cd727ba3a4773345.
Report an issue: GitHub.