gastownhall/beads · error

failed to fingerprint target changes: %w

Error message

failed to fingerprint target changes: %w

What it means

To detect uncommitted changes, bd hashes the contents of every path reported dirty by `git status --porcelain=v1 -z`. This error wraps failures from walking/hashing those changed files (permissions, concurrent deletion, stat errors) — missing files are tolerated (`<missing>`), but other I/O failures abort.

Source

Thrown at cmd/bd/worktree_cmd.go:1036

	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,
		gitDirInfo:           gitDirInfo,
		gitMarkerInfo:        gitMarkerInfo,
		gitDirFingerprint:    gitDirFingerprint,
		gitMarkerFingerprint: gitMarkerFingerprint,
		commonDir:            filepath.Clean(strings.TrimSpace(string(commonDirOutput))),
		headOID:              headOID,
		branch:               worktree.branch,
		detached:             worktree.detached,
		bare:                 worktree.bare,
		locked:               worktree.locked,
		lockReason:           worktree.lockReason,
		prunable:             worktree.prunable,

View on GitHub (pinned to 71377f2769)

Solutions

  1. Fix read permissions on the changed files: `chmod -R u+rwX <worktree>`
  2. Commit or discard the changes first (`git add -A && git commit` or `git checkout -- .`), then remove with a clean status
  3. If you accept data loss, use the force flag to bypass the cleanliness fingerprint entirely

Example fix

// before: unreadable modified file blocks fingerprint
chmod u+rw src/main.go
// after
bd worktree remove mywt
Defensive patterns

Strategy: validation

Validate before calling

// every dirty path should be readable before removal
out, _ := exec.Command("git", "-C", wt, "status", "--porcelain=v1", "-z").Output()
for _, p := range strings.Split(string(out), "\x00") {
    if len(p) > 3 {
        if _, err := os.Stat(filepath.Join(wt, p[3:])); err != nil && !os.IsNotExist(err) {
            return fmt.Errorf("unreadable changed file %s: %w", p[3:], err)
        }
    }
}

Prevention

When it happens

Trigger: `bd worktree remove <name>` without --force when a modified/untracked file listed by `git status` cannot be read: permission denied, unreadable symlink target handling, or transient I/O failures during the walk.

Common situations: Root-owned or 000-permission modified files; files locked by another process (Windows editors, AV); sparse-checkout entries with odd permissions; FUSE mount errors on untracked files.

Related errors


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