gastownhall/beads · error
target git directory identity changed (contents mismatch)
Error message
target git directory identity changed (contents mismatch)
What it means
Raised during the revalidation phase of `bd worktree remove`: although the worktree's git admin directory is still the same inode (identity check passed), its CONTENTS no longer match the fingerprint captured at plan time. This means something wrote into the admin directory (e.g. HEAD moved, new refs, config edits, index updates) after the removal plan was built, so bd aborts rather than removing a directory in a state different from what was inspected.
Source
Thrown at cmd/bd/worktree_cmd.go:1466
facts.TargetDirectory = worktreeremove.InvariantChanged
return worktreeRevalidationObservation{facts: facts, err: fmt.Errorf("target directory identity changed")}
}
facts.TargetDirectory = worktreeremove.InvariantStable
if !os.SameFile(currentTarget.gitDirInfo, plan.target.gitDirInfo) ||
!samePinnedFileMetadata(currentTarget.gitDirInfo, plan.target.gitDirInfo) {
facts.GitAdminDirectory = worktreeremove.InvariantChanged
return worktreeRevalidationObservation{facts: facts, err: fmt.Errorf("target git directory identity changed")}
}
facts.GitAdminDirectory = worktreeremove.InvariantStable
if !os.SameFile(currentTarget.gitMarkerInfo, plan.target.gitMarkerInfo) ||
!samePinnedFileMetadata(currentTarget.gitMarkerInfo, plan.target.gitMarkerInfo) {
facts.GitMarker = worktreeremove.InvariantChanged
return worktreeRevalidationObservation{facts: facts, err: fmt.Errorf("target git marker identity changed")}
}
facts.GitMarker = worktreeremove.InvariantStable
if currentTarget.gitDirFingerprint != plan.target.gitDirFingerprint {
facts.GitAdminDirectoryBytes = worktreeremove.InvariantChanged
return worktreeRevalidationObservation{facts: facts, err: fmt.Errorf("target git directory identity changed (contents mismatch)")}
}
facts.GitAdminDirectoryBytes = worktreeremove.InvariantStable
if currentTarget.gitMarkerFingerprint != plan.target.gitMarkerFingerprint {
facts.GitMarkerBytes = worktreeremove.InvariantChanged
return worktreeRevalidationObservation{facts: facts, err: fmt.Errorf("registered target identity changed (git marker mismatch)")}
}
facts.GitMarkerBytes = worktreeremove.InvariantStable
if plan.gitignoreCleanup != nil {
if err := plan.gitignoreCleanup.validate(); err != nil {
facts.ManagedIgnore = worktreeremove.InvariantChanged
return worktreeRevalidationObservation{facts: facts, err: fmt.Errorf(".gitignore changed before removal: %w", err)}
}
}
facts.ManagedIgnore = worktreeremove.InvariantStable
if plan.comparator == nil {
facts.Comparator = worktreeremove.InvariantNotRequired
facts.Containment = worktreeremove.InvariantNotRequiredView on GitHub (pinned to 71377f2769)
Solutions
- Re-run `bd worktree remove` so the plan is rebuilt with the current admin-directory fingerprint
- Stop concurrent git activity in the worktree (auto-fetch, IDE git integration, other agents) before removing
- Check `git -C <worktree> log --oneline -1` and `git worktree list` to see what changed since planning; confirm the current state is safe to remove
- If the new contents include unmerged or valuable work, export it (commit/stash/branch) before removal
Example fix
// before: fetch/commit running in the worktree while plan is stale plan := buildRemovalPlan(target) gitFetchInBackground(worktree) executeRemoval(plan) // fails: contents mismatch // after: quiesce the worktree, then plan and remove waitForGitQuiesce(worktree) plan := buildRemovalPlan(target) executeRemoval(plan)
Defensive patterns
Strategy: validation
Validate before calling
// Ensure no git process is active in the worktree before planning removal:
out, err := exec.Command("git", "-C", worktreePath, "status", "--porcelain").Output()
if err != nil { return err } // worktree must be a stable, working repo
// Disable background maintenance that would mutate the admin dir:
exec.Command("git", "-C", worktreePath, "config", "maintenance.auto", "false").Run() Try / catch
err := bdWorktreeRemove(path)
if err != nil && strings.Contains(err.Error(), "contents mismatch") {
// admin dir contents changed (HEAD/refs/config): inspect then retry
inspectWorktree(path)
err = rebuildPlanAndRemove(path)
} Prevention
- Quiesce the worktree: no commits, fetches, rebase, or gc between plan and execution
- Disable git auto-maintenance/background fetch for worktrees slated for removal
- Run removal from a single serialized workflow, not in parallel with other git operations
- Check `git -C <worktree> log -1` before and after planning to confirm HEAD is stable
When it happens
Trigger: Calling `bd worktree remove` where, between plan and execution, any file inside the worktree's `.git` admin directory changed content: a `git commit`/`fetch`/`rebase` updated HEAD or refs, `git config` edits, gc ran, or another agent executed git commands in that worktree.
Common situations: A background process or IDE auto-fetching in the worktree; another agent committing in the worktree while a remove was queued; cron jobs running `git gc` or `git maintenance`; running removal from a script that also performs git operations on the same worktree.
Related errors
- registered target identity changed (git marker mismatch)
- target HEAD disagrees with git worktree registry (registry %
- target is no longer registered at %s
- registered target identity changed
- target git directory changed
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/1a4fd52a81cb4fd4.
Report an issue: GitHub.