{"record":{"id":"a9d9d86a2c0f0a49","repo":"gastownhall/beads","slug":"reading-custom-statuses-for-reference-scan-w","errorCode":null,"errorMessage":"reading custom statuses for reference scan: %w","messagePattern":"reading custom statuses for reference scan: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/sweep.go","lineNumber":96,"sourceCode":"// transaction the candidates came off.\n//\n// Reading the workspace's custom statuses is required rather than best-effort:\n// an error aborts the sweep, because a scan that silently missed a custom active\n// status would under-protect and delete a bead a live bead still cites\n// (issueops.SweepRequest.ProtectReferenced).\nfunc sweepReferencedInTx(ctx context.Context, tx *sql.Tx, candidates []*types.Issue) (map[string]bool, error) {\n\tif len(candidates) == 0 {\n\t\treturn nil, nil\n\t}\n\tcandidateIDs := make(map[string]bool, len(candidates))\n\tfor _, issue := range candidates {\n\t\tcandidateIDs[issue.ID] = true\n\t}\n\tmatcher := workapi.NewCandidateIDMatcher(candidateIDs)\n\n\tcustom, err := ResolveCustomStatusesDetailedInTx(ctx, tx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"reading custom statuses for reference scan: %w\", err)\n\t}\n\tnotDone, err := SearchIssuesInTx(ctx, tx, \"\", workapi.BuildSweepReferenceScanFilter(custom))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"scanning open beads for references: %w\", err)\n\t}\n\n\tnotDoneIDs := make([]string, 0, len(notDone))\n\tfor _, issue := range notDone {\n\t\tif issue != nil {\n\t\t\tnotDoneIDs = append(notDoneIDs, issue.ID)\n\t\t}\n\t}\n\tcomments, err := GetCommentsForIssuesInTx(ctx, tx, notDoneIDs)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"scanning open beads for references: %w\", err)\n\t}\n\n\treferenced := make(map[string]bool)","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/sweep.go#L78-L114","documentation":"When ProtectReferenced is set, sweepReferencedInTx must first resolve the workspace's custom statuses via ResolveCustomStatusesDetailedInTx; a failure here is wrapped with this message. The comment in sweep.go states this is deliberately NOT best-effort: an error aborts the sweep, because silently missing a custom active status would under-protect and delete a bead a live bead still cites.","triggerScenarios":"ResolveCustomStatusesDetailedInTx fails due to a missing/corrupt config or statuses storage, a broken connection/tx, or a cancelled context — while running a sweep with ProtectReferenced enabled (the default protection path of `bd prune`/`bd purge`).","commonSituations":"A workspace with hand-edited or corrupted custom-status configuration; database unavailability mid-sweep; version migration left custom status metadata unreadable; context timeout on large workspaces.","solutions":["Inspect the wrapped error from ResolveCustomStatusesDetailedInTx — fix the underlying custom-status config or storage problem.","Do NOT retry deletion without protection: this failure is fail-safe by design to prevent deleting referenced beads.","Repair or regenerate the custom-status configuration (reset to defaults if corrupted) and re-run the sweep.","Ensure the database connection and context are healthy, then retry the sweep in dry-run first."],"exampleFix":"// before\nresult, err := SweepInTx(ctx, tx, req) // aborts: custom statuses unreadable\n// after\nif _, err := store.ResolveCustomStatusesDetailed(ctx); err != nil {\n    return fmt.Errorf(\"fix custom statuses before sweeping: %w\", err) // fail-safe\n}\nresult, err = SweepInTx(ctx, tx, req)","handlingStrategy":"fallback","validationCode":"// pre-resolve custom statuses so an unreadable config surfaces before sweeping\ncustom, err := issueops.ResolveCustomStatusesDetailed(ctx)\nif err != nil { return fmt.Errorf(\"resolve custom statuses before sweep: %w\", err) }","typeGuard":null,"tryCatchPattern":"result, err := issueops.SweepInTx(ctx, tx, req)\nif err != nil && strings.Contains(err.Error(), \"reading custom statuses for reference scan\") {\n    // fail-safe: nothing was deleted; fix config, do NOT bypass protection\n    return fmt.Errorf(\"sweep aborted to protect referenced beads: %w\", err)\n}","preventionTips":["Never bypass ProtectReferenced when its prerequisite reads fail","Keep custom-status config valid; reset to defaults if corrupted","Validate config after upgrades and hand edits","Dry-run sweeps to catch this before a real deletion"],"tags":["go","sweep","configuration","fail-safe"],"backgroundTag":"custom-status-resolution-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}