{"record":{"id":"d3d39df611e7dce1","repo":"gastownhall/beads","slug":"delete-count-events-w","errorCode":null,"errorMessage":"delete: count events: %w","messagePattern":"delete: count events: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/domain/issue_delete.go","lineNumber":135,"sourceCode":"\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\n\tvar connected map[string]*types.Issue\n\tvar connectedIsWisp map[string]bool\n\tif params.UpdateTextReferences {\n\t\tdeletedSet := make(map[string]bool, len(allIDs))\n\t\tfor _, id := range allIDs {\n\t\t\tdeletedSet[id] = true","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/domain/issue_delete.go#L117-L153","documentation":"deleteMany wraps errors from eventsRepo.CountAllForIDs on the regular-issues table when gathering pre-delete event counts for the result. The 'delete: count events:' prefix marks the failing step; the driver error is preserved via %w. Deletion has not started.","triggerScenarios":"Any deleteMany invocation reaching the events-count phase when CountAllForIDs(ctx, regularIDs, RecordEventOpts{}) fails — DB connection error, SQL error on the events table, storage unavailable.","commonSituations":"Bulk issue deletes with event-history tables under load; schema drift on events tables after version upgrades; Dolt restart during a delete batch.","solutions":["Inspect the wrapped error from CountAllForIDs","Verify Dolt health and events-table schema","Retry the delete; it is non-destructive at this point","Batch very large deletes to reduce table-scan pressure"],"exampleFix":"// before\nres, err := uc.DeleteIssues(ctx, ids, actor)\nif err != nil { return err }\n// after\nif err != nil {\n\tif strings.Contains(err.Error(), \"count events\") {\n\t\tlog.Printf(\"event count failed before delete: %v\", err)\n\t}\n\treturn err\n}","handlingStrategy":"retry","validationCode":"if err := pingDolt(ctx); err != nil {\n\treturn fmt.Errorf(\"storage down, deferring delete: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"res, err := uc.DeleteIssues(ctx, ids, actor)\nif err != nil && strings.Contains(err.Error(), \"count events\") {\n\t// events count failed pre-delete; safe to retry\n\treturn retryDelete(ctx, ids)\n}","preventionTips":["Check events-table schema after beads upgrades","Avoid delete batches during peak Dolt load","Retry pre-delete stat failures rather than treating them as destructive failures"],"tags":["go","delete","events","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"}