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

  1. Confirm the target is really a linked git worktree (`git worktree list`) and not a nested clone or submodule
  2. If it is a nested clone, remove it as a normal directory instead of via worktree removal
  3. 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

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


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