gastownhall/beads · error
target git marker is not a regular file: %s
Error message
target git marker is not a regular file: %s
What it means
A linked worktree must contain a regular `.git` file (a symlink or directory is rejected). bd rejects the removal target when `os.Lstat` shows the `.git` marker is a symlink or not a regular file, because fingerprinting and identity checks assume the standard git layout.
Source
Thrown at cmd/bd/worktree_cmd.go:1024
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))
if err != nil {
return pinnedWorktreeTarget{}, fmt.Errorf("failed to fingerprint target changes: %w", err)
}
return pinnedWorktreeTarget{
path: filepath.Clean(worktree.path),
pathInfo: pathInfo,
gitDir: gitDir,View on GitHub (pinned to 71377f2769)
Solutions
- Confirm the target is really a linked git worktree (`git worktree list`) and not a nested clone or submodule
- If it is a nested clone, remove it as a normal directory instead of via worktree removal
- If it should be a worktree, recreate it with `git worktree add` so `.git` is a regular file
Example fix
// before: nested clone used as worktree mv mywt/ mywt.bak && git worktree add mywt -b mybranch // after: .git is a regular pointer file and removal succeeds
Defensive patterns
Strategy: validation
Validate before calling
info, err := os.Lstat(filepath.Join(worktreePath, ".git"))
if err != nil || info.Mode()&os.ModeSymlink != 0 || !info.Mode().IsRegular() {
return fmt.Errorf("refusing: %s/.git is not a regular file", worktreePath)
} Type guard
func isLinkedWorktree(path string) bool {
info, err := os.Lstat(filepath.Join(path, ".git"))
return err == nil && info.Mode()&os.ModeSymlink == 0 && info.Mode().IsRegular()
} Prevention
- Only register directories created by `git worktree add` as worktrees
- Distinguish nested clones/submodules from linked worktrees before removal
- Keep submodule checkouts out of `bd worktree` operations
When it happens
Trigger: `bd worktree remove <name>` or revalidation when `<worktree>/.git` is a symlink (common with submodules) or a directory (an embedded clone).
Common situations: Adding a submodule checkout or a plain nested clone and registering it as a 'worktree'; switching tooling that replaces .git with a symlink; manual restructuring of worktree directories.
Related errors
- git returned invalid commit object ID %q
- worktree removal mode is absent or invalid
- cannot remove the primary worktree
- cannot remove the worktree containing the running command
- registered worktree target is absent or invalid
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/38d4f0c7ec82cd6c.
Report an issue: GitHub.