gastownhall/beads · warning
db: LabelSQLRepository.DeleteAllForIDs rows affected: %w
Error message
db: LabelSQLRepository.DeleteAllForIDs rows affected: %w
What it means
LabelSQLRepository.DeleteAllForIDs executed the DELETE but res.RowsAffected() returned an error, so the number of deleted rows could not be determined. This is a driver capability/transport issue, not a failed delete.
Source
Thrown at internal/storage/domain/db/label.go:222
placeholders := make([]string, len(batch))
args := make([]any, len(batch))
for i, id := range batch {
placeholders[i] = "?"
args[i] = id
}
//nolint:gosec // G201: table is one of two hardcoded constants; ? placeholders only.
res, err := r.runner.ExecContext(ctx,
fmt.Sprintf("DELETE FROM %s WHERE issue_id IN (%s)", table, strings.Join(placeholders, ",")),
args...)
if err != nil {
if opts.UseWispsTable && dberrors.IsTableNotExist(err) {
return total, nil
}
return total, fmt.Errorf("db: LabelSQLRepository.DeleteAllForIDs from %s: %w", table, err)
}
n, err := res.RowsAffected()
if err != nil {
return total, fmt.Errorf("db: LabelSQLRepository.DeleteAllForIDs rows affected: %w", err)
}
total += int(n)
}
return total, nil
}
func (r *labelSQLRepositoryImpl) CountAllForIDs(ctx context.Context, ids []string, opts domain.LabelOpts) (int, error) {
if len(ids) == 0 {
return 0, nil
}
table := "labels"
if opts.UseWispsTable {
table = "wisp_labels"
}
count, err := issueops.CountRowsForIssueIDsInTx(ctx, r.runner, table, ids)
if err != nil {
if opts.UseWispsTable && dberrors.IsTableNotExist(err) {
return 0, nilView on GitHub (pinned to 71377f2769)
Solutions
- Unwrap the error to see which driver call failed
- Check the storage driver supports RowsAffected for DML (upgrade driver if not)
- If using a mock/test runner, implement RowsAffected in the stub result
- Treat total as best-effort only if your use case does not need exact counts (may require upstream change)
Example fix
// before
// stub result without RowsAffected
type fakeResult struct{}
// after
type fakeResult struct{ n int64 }
func (f fakeResult) RowsAffected() (int64, error) { return f.n, nil }
func (f fakeResult) LastInsertId() (int64, error) { return 0, nil } Defensive patterns
Strategy: fallback
Validate before calling
// prefer drivers known to support RowsAffected; avoid stub runners in prod paths
Try / catch
n, err := repo.DeleteAllForIDs(ctx, ids, opts)
if err != nil && strings.Contains(err.Error(), "rows affected") {
// delete likely succeeded; treat count as unknown
log.Printf("delete ok, count unknown: %v", err)
return nil
} Prevention
- Use a driver whose Result implements RowsAffected
- Implement RowsAffected in test mocks
- Only rely on returned counts when the driver guarantees them
- Upgrade driver versions with known metadata fixes
When it happens
Trigger: Calling DeleteAllForIDs against a driver/connection that does not support or fails to report rows affected (e.g. some drivers return driver.ErrSkip or transport errors).
Common situations: Using a driver or proxy that does not implement RowsAffected; connection interruption right after statement execution; mock/stub runners in tests lacking RowsAffected support.
Related errors
- failed to check rows affected for issue counter prefix %q: %
- failed to check rows affected after seeding for prefix %q: %
- failed to open migration connection: %w
- db: DependencySQLRepository.DeleteAllForIDs rows affected: %
- db: EventsSQLRepository.DeleteAllForIDs rows affected: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/6732378f16b86236.
Report an issue: GitHub.