{"record":{"id":"d76d7d57511dbc50","repo":"gastownhall/beads","slug":"failed-to-remove-s-w","errorCode":null,"errorMessage":"failed to remove %s: %w","messagePattern":"failed to remove (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/bd/doctor/maintenance.go","lineNumber":303,"sourceCode":"\t\tStatus:   StatusWarning,\n\t\tMessage:  fmt.Sprintf(\"%d stale .beads/mq/*.json file(s)\", len(files)),\n\t\tDetail:   \"Legacy orchestrator merge queue files (local only, safe to delete)\",\n\t\tFix:      \"Run 'bd doctor --fix' to delete, or 'rm -rf .beads/mq/'\",\n\t\tCategory: CategoryMaintenance,\n\t}\n}\n\n// FixStaleMQFiles removes the legacy .beads/mq/ directory and all its contents.\nfunc FixStaleMQFiles(path string) error {\n\tbeadsDir := ResolveBeadsDirForRepo(path)\n\tmqDir := filepath.Join(beadsDir, \"mq\")\n\n\tif _, err := os.Stat(mqDir); os.IsNotExist(err) {\n\t\treturn nil // Nothing to do\n\t}\n\n\tif err := os.RemoveAll(mqDir); err != nil {\n\t\treturn fmt.Errorf(\"failed to remove %s: %w\", mqDir, err)\n\t}\n\n\treturn nil\n}\n\n// checkMisclassifiedWisps detects wisp-patterned issues that lack the ephemeral flag.\n// Issues with IDs containing \"-wisp-\" should always have Ephemeral=true.\n// If they're in the issue store without the ephemeral flag, they'll pollute bd ready.\nfunc checkMisclassifiedWisps(path string) DoctorCheck {\n\tissues, err := loadMisclassifiedWispIssues(path)\n\tif err != nil {\n\t\treturn DoctorCheck{\n\t\t\tName:     \"Misclassified Wisps\",\n\t\t\tStatus:   StatusOK,\n\t\t\tMessage:  maintenanceIssuesUnavailableMessage,\n\t\t\tCategory: CategoryMaintenance,\n\t\t}\n\t}","sourceCodeStart":285,"sourceCodeEnd":321,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/doctor/maintenance.go#L285-L321","documentation":"FixStaleMQFiles deletes the stale message-queue directory with os.RemoveAll after confirming it exists. If RemoveAll fails (it reports the first error encountered while walking/removing), the path and cause are wrapped in this error. It means stale mq cleanup could not complete and stale files remain.","triggerScenarios":"os.RemoveAll(mqDir) returns an error — typically EACCES/EPERM on files or parent dirs inside mqDir, a read-only filesystem, or another process holding an unavoidable lock on Windows.","commonSituations":"The .beads mq directory is owned by root or another user; a concurrently running bd process recreated/locked files mid-delete; read-only CI filesystem; immutable files left by a crashed process.","solutions":["Fix ownership/permissions on the mq directory: sudo chown -R $(whoami) <mqDir> then retry.","Stop other bd processes that may hold files open, then re-run bd doctor --fix.","Remove the directory manually if permitted: rm -rf <mqDir>.","Check the filesystem is writable (mount rw) and files are not immutable (chattr -i)."],"exampleFix":"// before\n$ bd doctor --fix\nError: failed to remove /repo/.beads/mq: permission denied\n// after\n$ sudo chown -R $(whoami) .beads/mq\n$ bd doctor --fix\n✓ stale mq files removed","handlingStrategy":"validation","validationCode":"if info, err := os.Stat(mqDir); err == nil {\n    if err := syscall.Access(mqDir, os.W_OK); err != nil {\n        return fmt.Errorf(\"precheck: mq dir %s not writable: %v\", mqDir, err)\n    }\n}","typeGuard":null,"tryCatchPattern":"if err := doctor.FixStaleMQFiles(path); err != nil {\n    if strings.Contains(err.Error(), \"failed to remove\") {\n        // fall back to manual cleanup or chown then retry once\n    }\n    return err\n}","preventionTips":["Ensure one bd process at a time touches the .beads directory.","Keep .beads owned by the user running bd.","Avoid read-only mounts for repos where doctor --fix will run.","Clear immutable attributes (chattr -i) if files were hardened."],"tags":["filesystem","cleanup","permissions"],"backgroundTag":"directory-removal-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}