gastownhall/beads · error

worktree contains modified, untracked, or ignored files

Error message

worktree contains modified, untracked, or ignored files

What it means

Prepare rejects the request because mode is Normal but facts.Status is Dirty. The worktree contains modified, untracked, or ignored files, and normal (non-force) removal refuses to destroy uncommitted work. Force mode bypasses this check.

Source

Thrown at internal/worktreeremove/policy.go:202

		facts.TargetDir != Present || facts.GitAdminDir != Present ||
		facts.GitMarker != Present || facts.Head != Present {
		return Plan{}, fmt.Errorf("registered worktree target is absent or invalid")
	}
	if facts.CommonDir != Matched {
		return Plan{}, fmt.Errorf("target common git directory does not match repository")
	}
	if facts.Status != Clean && facts.Status != Dirty {
		return Plan{}, fmt.Errorf("worktree cleanliness observation is absent or invalid")
	}
	if facts.ManagedIgnore != IgnoreAbsent && facts.ManagedIgnore != IgnoreManaged {
		return Plan{}, fmt.Errorf("managed ignore observation is absent or invalid")
	}
	if (facts.ManagedIgnore == IgnoreManaged) != (facts.ManagedIgnoreEntry != "") {
		return Plan{}, fmt.Errorf("managed ignore cleanup identity is absent or invalid")
	}
	if request.Mode != Force {
		if facts.Status != Clean {
			return Plan{}, fmt.Errorf("worktree contains modified, untracked, or ignored files")
		}
		if facts.Comparator != ComparatorAvailable && facts.Comparator != ComparatorMissing && facts.Comparator != ComparatorNotRequired {
			return Plan{}, fmt.Errorf("worktree comparison target observation is absent or invalid")
		}
		if facts.Comparator != ComparatorAvailable {
			return Plan{}, fmt.Errorf("cannot verify unpushed commits: no comparison target is available")
		}
		if facts.Containment != Contained && facts.Containment != NotContained && facts.Containment != ContainmentNotRequired {
			return Plan{}, fmt.Errorf("worktree containment observation is absent or invalid")
		}
		if facts.Containment != Contained {
			return Plan{}, fmt.Errorf("worktree HEAD is not contained in the comparison target")
		}
	} else if facts.Comparator != ComparatorNotRequired || facts.Containment != ContainmentNotRequired {
		return Plan{}, fmt.Errorf("worktree force-mode comparison observations are inconsistent")
	}
	plan := Plan{approved: true, mode: request.Mode, targetPath: facts.RegisteredPath}
	if facts.ManagedIgnore == IgnoreManaged {

View on GitHub (pinned to 71377f2769)

Solutions

  1. Commit or remove the local changes in the worktree, then retry
  2. Run git clean -fd / git checkout -- . in the worktree if the files are disposable
  3. Use Request{Mode: Force} only after confirming the changes are safe to discard

Example fix

// before
plan, err := worktreeremove.Prepare(worktreeremove.Request{Mode: worktreeremove.Normal}, facts) // facts.Status == Dirty
// after
// commit/discard changes so git status is clean, or:
plan, err := worktreeremove.Prepare(worktreeremove.Request{Mode: worktreeremove.Force}, facts)
Defensive patterns

Strategy: validation

Validate before calling

if req.Mode == worktreeremove.Normal && facts.Status == worktreeremove.Dirty {
	return fmt.Errorf("worktree %s is dirty; commit or use Force", facts.RegisteredPath)
}

Type guard

func safeForNormalRemoval(f worktreeremove.PrepareFacts) bool {
	return f.Status == worktreeremove.Clean
}

Try / catch

plan, err := worktreeremove.Prepare(req, facts)
if err != nil && strings.Contains(err.Error(), "modified, untracked, or ignored") {
	return fmt.Errorf("worktree has local changes; commit, clean, or pass Force: %w", err)
}

Prevention

When it happens

Trigger: Calling Prepare with Request{Mode: Normal} while the worktree has a dirty git status (modified tracked files, untracked files, or ignored files per the adapter's definition).

Common situations: A developer left local edits or build artifacts in the worktree; untracked generated files count as dirty; attempting scripted cleanup of active worktrees.

Related errors


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