{"record":{"id":"f251305ac15f6c82","repo":"gastownhall/beads","slug":"delete-count-wisp-labels-w","errorCode":null,"errorMessage":"delete: count wisp labels: %w","messagePattern":"delete: count wisp labels: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/domain/issue_delete.go","lineNumber":129,"sourceCode":"\n\twispIDs, regularIDs, err := u.issueRepo.PartitionWispIDs(ctx, allIDs)\n\tif err != nil {\n\t\treturn DeleteIssuesResult{}, fmt.Errorf(\"delete: partition: %w\", err)\n\t}\n\n\tdepCount, err := u.countDeletedDependencies(ctx, allIDs)\n\tif err != nil {\n\t\treturn DeleteIssuesResult{}, err\n\t}\n\tresult.DependenciesCount = depCount\n\n\tlabelIssue, err := u.labelRepo.CountAllForIDs(ctx, regularIDs, LabelOpts{})\n\tif err != nil {\n\t\treturn DeleteIssuesResult{}, fmt.Errorf(\"delete: count labels: %w\", err)\n\t}\n\tlabelWisp, err := u.labelRepo.CountAllForIDs(ctx, wispIDs, LabelOpts{UseWispsTable: true})\n\tif err != nil {\n\t\treturn DeleteIssuesResult{}, fmt.Errorf(\"delete: count wisp labels: %w\", err)\n\t}\n\tresult.LabelsCount = labelIssue + labelWisp\n\n\tevIssue, err := u.eventsRepo.CountAllForIDs(ctx, regularIDs, RecordEventOpts{})\n\tif err != nil {\n\t\treturn DeleteIssuesResult{}, fmt.Errorf(\"delete: count events: %w\", err)\n\t}\n\tevWisp, err := u.eventsRepo.CountAllForIDs(ctx, wispIDs, RecordEventOpts{UseWispsTable: true})\n\tif err != nil {\n\t\treturn DeleteIssuesResult{}, fmt.Errorf(\"delete: count wisp events: %w\", err)\n\t}\n\tresult.EventsCount = evIssue + evWisp\n\n\tif params.DryRun {\n\t\tresult.DeletedCount = len(regularIDs) + len(wispIDs)\n\t\treturn result, nil\n\t}\n","sourceCodeStart":111,"sourceCodeEnd":147,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/domain/issue_delete.go#L111-L147","documentation":"deleteMany wraps errors from labelRepo.CountAllForIDs on the wisps table (UseWispsTable: true) while gathering pre-delete label stats. The 'delete: count wisp labels:' prefix identifies this specific counting step. Deletion has not begun.","triggerScenarios":"Any deleteMany path where CountAllForIDs(ctx, wispIDs, LabelOpts{UseWispsTable: true}) fails — wisps table missing/inaccessible, SQL error, or DB connection failure.","commonSituations":"Deletes that include wisps in newer beads versions where the wisps table schema changed; Dolt migration mid-flight; wisp table permissions issues.","solutions":["Unwrap to find the wisp-table CountAllForIDs failure","Confirm the wisps table exists with the expected schema (run beads upgrade if versions drifted)","Retry the delete — safe, nothing deleted yet","Check Dolt connection health"],"exampleFix":"// before\nres, err := uc.DeleteWisps(ctx, wispIDs, actor)\nif err != nil { return err }\n// after\nif err != nil && strings.Contains(err.Error(), \"count wisp labels\") {\n\t// wisps table read failed before any deletion — verify schema, then retry\n\treturn err\n}","handlingStrategy":"retry","validationCode":"if err := pingDolt(ctx); err != nil {\n\treturn fmt.Errorf(\"storage unavailable: %w\", err)\n}\n// ensure wisps table present before wisp deletes","typeGuard":null,"tryCatchPattern":"res, err := uc.DeleteWisps(ctx, ids, actor)\nif err != nil && strings.Contains(err.Error(), \"count wisp labels\") {\n\t// wisp-table read failed before any deletion — upgrade schema if drifted, then retry\n\treturn err\n}","preventionTips":["Run beads upgrade after version changes so wisp tables match expectations","Schedule wisp cleanup jobs when Dolt is stable","Retry — this failure happens before any data is modified"],"tags":["go","delete","wisp","labels","count"],"backgroundTag":"storage-operation-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}