{"record":{"id":"8fd85efbff4b30a0","repo":"gastownhall/beads","slug":"delete-count-labels-w","errorCode":null,"errorMessage":"delete: count labels: %w","messagePattern":"delete: count labels: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/domain/issue_delete.go","lineNumber":125,"sourceCode":"\t}\n\tif len(allIDs) == 0 {\n\t\treturn DeleteIssuesResult{}, nil\n\t}\n\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 {","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/domain/issue_delete.go#L107-L143","documentation":"deleteMany wraps errors from labelRepo.CountAllForIDs on the regular-issues table when pre-deleting label counts are gathered for the result stats. The 'delete: count labels:' prefix marks the failure; the underlying repository error is preserved via %w. No deletion has occurred yet.","triggerScenarios":"DeleteIssue/DeleteIssues/DeleteWisps/DeleteWisp reaching the stats-counting phase when CountAllForIDs(ctx, regularIDs, LabelOpts{}) fails — DB error, missing labels table, or connection loss.","commonSituations":"Deletes with result-stat collection running against a Dolt instance with schema drift or an in-progress migration; connection pool exhaustion during bulk deletes.","solutions":["Unwrap the error to see the CountAllForIDs driver failure","Verify the labels table exists and Dolt is healthy","Retry the delete; deletion has not started, so it is safe","If stats are non-essential, consider whether the library offers a mode that tolerates count failures"],"exampleFix":"// before\nres, err := uc.DeleteIssues(ctx, ids, actor)\n// after\nif err != nil {\n\tif strings.Contains(err.Error(), \"count labels\") {\n\t\tlog.Printf(\"label count failed, nothing deleted: %v\", err)\n\t}\n\treturn err\n}","handlingStrategy":"retry","validationCode":"if err := pingDolt(ctx); err != nil {\n\treturn fmt.Errorf(\"storage unavailable, skipping delete: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"res, err := uc.DeleteIssues(ctx, ids, actor)\nif err != nil && strings.Contains(err.Error(), \"count labels\") {\n\t// stats phase failed; nothing deleted — retry after health check\n\treturn retryDelete(ctx, ids)\n}","preventionTips":["Verify labels-table schema matches the installed beads version","Avoid deletes during Dolt migrations or restarts","Treat pre-delete stat failures as safe-to-retry conditions"],"tags":["go","delete","labels","count","wrapped-error"],"backgroundTag":"storage-operation-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}