{"record":{"id":"f8cfd5d464c36a18","repo":"gastownhall/beads","slug":"count-dependencies-w","errorCode":null,"errorMessage":"count dependencies: %w","messagePattern":"count dependencies: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/delete.go","lineNumber":213,"sourceCode":"// neighborhood BEFORE the delete and rewrite it AFTER against the SAME\n// DeletionSet the delete was handed.\n//\n//nolint:gosec // G201: inClause contains only ? placeholders\nfunc DeleteResolvedSetInTx(ctx context.Context, tx *sql.Tx, set DeletionSet, dryRun bool) (*types.DeleteIssuesResult, error) {\n\tresult := &types.DeleteIssuesResult{}\n\tif len(set.All) == 0 {\n\t\treturn result, nil\n\t}\n\n\tdeletedSet := make(map[string]bool, len(set.All))\n\tfor _, id := range set.All {\n\t\tdeletedSet[id] = true\n\t}\n\n\tvar depsCount, labelsCount, eventsCount int\n\tvar err error\n\tif depsCount, err = CountRowsForIssueIDsInTx(ctx, tx, \"dependencies\", set.RegularIDs); err != nil {\n\t\treturn nil, fmt.Errorf(\"count dependencies: %w\", err)\n\t}\n\twispDepsCount, err := CountRowsForIssueIDsInTx(ctx, tx, \"wisp_dependencies\", set.WispIDs)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"count wisp dependencies: %w\", err)\n\t}\n\tdepsCount += wispDepsCount\n\n\tif labelsCount, err = CountRowsForIssueIDsInTx(ctx, tx, \"labels\", set.RegularIDs); err != nil {\n\t\treturn nil, fmt.Errorf(\"count labels: %w\", err)\n\t}\n\twispLabelsCount, err := CountRowsForIssueIDsInTx(ctx, tx, \"wisp_labels\", set.WispIDs)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"count wisp labels: %w\", err)\n\t}\n\tlabelsCount += wispLabelsCount\n\n\tif eventsCount, err = CountRowsForIssueIDsInTx(ctx, tx, \"events\", set.RegularIDs); err != nil {\n\t\treturn nil, fmt.Errorf(\"count events: %w\", err)","sourceCodeStart":195,"sourceCodeEnd":231,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/delete.go#L195-L231","documentation":"DeleteResolvedSetInTx wraps a failure from CountRowsForIssueIDsInTx on the dependencies table (a later, distinct wrap covers wisp_dependencies). These counts feed the delete result/audit summary of how many child rows will disappear; the failure aborts before any rows are counted/deleted inconsistently.","triggerScenarios":"Bulk delete reaching the row-counting phase when the SELECT COUNT on dependencies for the regular ids fails: context expired mid-bulk-delete, connection dropped, or SQL error (e.g., table missing after schema drift).","commonSituations":"Very large bulk deletes whose context budget runs out during counting; schema drift after an upgrade removing/renaming the dependencies table; transient Dolt server errors on big IN(...) queries.","solutions":["Inspect the wrapped error; a missing 'dependencies' table means run schema migration.","Retry the delete with a longer-lived context sized to the batch.","Reduce batch size so counting stays within statement timeouts.","Retry in a fresh transaction if the cause was a dropped connection."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// schema pre-flight for the counted tables\nfor _, t := range []string{\"dependencies\", \"wisp_dependencies\"} {\n\tif err := tableExists(ctx, db, t); err != nil { return err }\n}","typeGuard":null,"tryCatchPattern":"res, err := storage.DeleteIssues(ctx, db, ids, cascade, force, dryRun)\nif err != nil {\n\tif errors.Is(err, context.DeadlineExceeded) { /* longer ctx, smaller batch */ }\n\tif strings.Contains(causeOf(err).Error(), \"no such table\") { /* run migrations */ }\n\treturn err\n}","preventionTips":["Run bd migrate after every version upgrade (missing 'dependencies' table = schema drift).","Use long-enough contexts so bulk deletes survive the counting phase.","Chunk very large id sets before deleting."],"tags":["database","bulk-delete","count","error-wrapping"],"backgroundTag":"transaction-query-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}