{"record":{"id":"09dac27bf98660c6","repo":"gastownhall/beads","slug":"worktree-contains-modified-untracked-or-ignored","errorCode":null,"errorMessage":"worktree contains modified, untracked, or ignored files","messagePattern":"worktree contains modified, untracked, or ignored files","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/worktreeremove/policy.go","lineNumber":202,"sourceCode":"\t\tfacts.TargetDir != Present || facts.GitAdminDir != Present ||\n\t\tfacts.GitMarker != Present || facts.Head != Present {\n\t\treturn Plan{}, fmt.Errorf(\"registered worktree target is absent or invalid\")\n\t}\n\tif facts.CommonDir != Matched {\n\t\treturn Plan{}, fmt.Errorf(\"target common git directory does not match repository\")\n\t}\n\tif facts.Status != Clean && facts.Status != Dirty {\n\t\treturn Plan{}, fmt.Errorf(\"worktree cleanliness observation is absent or invalid\")\n\t}\n\tif facts.ManagedIgnore != IgnoreAbsent && facts.ManagedIgnore != IgnoreManaged {\n\t\treturn Plan{}, fmt.Errorf(\"managed ignore observation is absent or invalid\")\n\t}\n\tif (facts.ManagedIgnore == IgnoreManaged) != (facts.ManagedIgnoreEntry != \"\") {\n\t\treturn Plan{}, fmt.Errorf(\"managed ignore cleanup identity is absent or invalid\")\n\t}\n\tif request.Mode != Force {\n\t\tif facts.Status != Clean {\n\t\t\treturn Plan{}, fmt.Errorf(\"worktree contains modified, untracked, or ignored files\")\n\t\t}\n\t\tif facts.Comparator != ComparatorAvailable && facts.Comparator != ComparatorMissing && facts.Comparator != ComparatorNotRequired {\n\t\t\treturn Plan{}, fmt.Errorf(\"worktree comparison target observation is absent or invalid\")\n\t\t}\n\t\tif facts.Comparator != ComparatorAvailable {\n\t\t\treturn Plan{}, fmt.Errorf(\"cannot verify unpushed commits: no comparison target is available\")\n\t\t}\n\t\tif facts.Containment != Contained && facts.Containment != NotContained && facts.Containment != ContainmentNotRequired {\n\t\t\treturn Plan{}, fmt.Errorf(\"worktree containment observation is absent or invalid\")\n\t\t}\n\t\tif facts.Containment != Contained {\n\t\t\treturn Plan{}, fmt.Errorf(\"worktree HEAD is not contained in the comparison target\")\n\t\t}\n\t} else if facts.Comparator != ComparatorNotRequired || facts.Containment != ContainmentNotRequired {\n\t\treturn Plan{}, fmt.Errorf(\"worktree force-mode comparison observations are inconsistent\")\n\t}\n\tplan := Plan{approved: true, mode: request.Mode, targetPath: facts.RegisteredPath}\n\tif facts.ManagedIgnore == IgnoreManaged {","sourceCodeStart":184,"sourceCodeEnd":220,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/worktreeremove/policy.go#L184-L220","documentation":"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.","triggerScenarios":"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).","commonSituations":"A developer left local edits or build artifacts in the worktree; untracked generated files count as dirty; attempting scripted cleanup of active worktrees.","solutions":["Commit or remove the local changes in the worktree, then retry","Run git clean -fd / git checkout -- . in the worktree if the files are disposable","Use Request{Mode: Force} only after confirming the changes are safe to discard"],"exampleFix":"// before\nplan, err := worktreeremove.Prepare(worktreeremove.Request{Mode: worktreeremove.Normal}, facts) // facts.Status == Dirty\n// after\n// commit/discard changes so git status is clean, or:\nplan, err := worktreeremove.Prepare(worktreeremove.Request{Mode: worktreeremove.Force}, facts)","handlingStrategy":"validation","validationCode":"if req.Mode == worktreeremove.Normal && facts.Status == worktreeremove.Dirty {\n\treturn fmt.Errorf(\"worktree %s is dirty; commit or use Force\", facts.RegisteredPath)\n}","typeGuard":"func safeForNormalRemoval(f worktreeremove.PrepareFacts) bool {\n\treturn f.Status == worktreeremove.Clean\n}","tryCatchPattern":"plan, err := worktreeremove.Prepare(req, facts)\nif err != nil && strings.Contains(err.Error(), \"modified, untracked, or ignored\") {\n\treturn fmt.Errorf(\"worktree has local changes; commit, clean, or pass Force: %w\", err)\n}","preventionTips":["Check git status before scripted worktree removal","Clean build artifacts that register as untracked","Reserve Force mode for reviewed, disposable worktrees"],"tags":["worktree","git","dirty-worktree"],"backgroundTag":"dirty-worktree","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}