{"record":{"id":"1a2d1e23ccb0ea5d","repo":"gastownhall/beads","slug":"delete-partition-w","errorCode":null,"errorMessage":"delete: partition: %w","messagePattern":"delete: partition: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/domain/issue_delete.go","lineNumber":114,"sourceCode":"\t\t\t}\n\t\t\tresult.OrphanedIssues = sortedStringSet(orphanSet)\n\t\t} else {\n\t\t\tfor _, id := range params.IDs {\n\t\t\t\tif deps := externalBySource[id]; len(deps) > 0 {\n\t\t\t\t\tsort.Strings(deps)\n\t\t\t\t\tresult.OrphanedIssues = deps\n\t\t\t\t\treturn result, &DeleteBlockedError{IssueID: id, Dependents: deps}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\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","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/domain/issue_delete.go#L96-L132","documentation":"deleteMany wraps errors from issueRepo.PartitionWispIDs, which splits the expanded ID set into wisps vs regular issues. The 'delete: partition:' prefix marks this step as the failure point. Deletion aborts before counting or deleting anything.","triggerScenarios":"Any deleteMany invocation (via DeleteIssue, DeleteWisp, DeleteIssues, DeleteWisps) reaching the partition step when PartitionWispIDs fails — DB connection error, SQL error in the ID-classification query, storage unavailable.","commonSituations":"Bulk deletes of mixed issue/wisp sets during Dolt unavailability; schema drift between wisp and issue tables; very large ID lists hitting query limits.","solutions":["Inspect the wrapped driver error from PartitionWispIDs","Verify Dolt connectivity and server health","Retry the delete — no data has been modified yet at this stage","For very large ID sets, delete in smaller batches"],"exampleFix":"// before\nres, err := uc.DeleteWisps(ctx, ids, actor)\nif err != nil { return err }\n// after\nif err != nil {\n\tif strings.Contains(err.Error(), \"delete: partition\") {\n\t\t// nothing deleted; retry after checking storage health\n\t}\n\treturn fmt.Errorf(\"batch delete: %w\", 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.DeleteWisps(ctx, ids, actor)\nif err != nil {\n\tif strings.Contains(err.Error(), \"delete: partition\") {\n\t\t// partition is read-only; nothing deleted — safe to retry\n\t\treturn retryDelete(ctx, ids)\n\t}\n\treturn err\n}","preventionTips":["Split very large ID sets into smaller batches before deleting","Check storage health before batch cleanup jobs","Retry deletes — the partition phase is non-destructive"],"tags":["go","delete","partition","wisp","wrapped-error"],"backgroundTag":"storage-operation-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}