gastownhall/beads · warning
rows affected: %w
Error message
rows affected: %w
What it means
After the DELETE, result.RowsAffected() is read to report how many issues were removed; an error there is wrapped as "rows affected: %w". The delete itself succeeded, but the affected-row count could not be retrieved.
Source
Thrown at internal/storage/issueops/bulk_ops.go:220
if _, err := tx.ExecContext(ctx,
`DELETE FROM leases WHERE issue_id IN (SELECT id FROM issues WHERE source_repo = ?)`, sourceRepo); err != nil {
return 0, fmt.Errorf("delete leases: %w", err)
}
// Edges are journaled before the rows go, while their source snapshots can
// still be read.
if err := RecordDependencyRemovalsForIssuesInTx(ctx, tx, issueIDs); err != nil {
return 0, fmt.Errorf("journal dependency removals for source-repo delete: %w", err)
}
result, err := tx.ExecContext(ctx, `DELETE FROM issues WHERE source_repo = ?`, sourceRepo)
if err != nil {
return 0, fmt.Errorf("delete issues: %w", err)
}
rowsAffected, err := result.RowsAffected()
if err != nil {
return 0, fmt.Errorf("rows affected: %w", err)
}
// Journal each deleted issue in the same transaction. issueIDs is the exact
// set removed by the DELETE above (both were scoped to source_repo), so
// there are no phantom records here. The source-repo bulk delete plumbing
// carries no actor, so the rows record none.
for _, id := range issueIDs {
if err := RecordDeleteInTx(ctx, tx, id, ""); err != nil {
return int(rowsAffected), err
}
}
if err := RecomputeIsBlockedInTx(ctx, tx, affectedIssues, affectedWisps); err != nil {
return int(rowsAffected), fmt.Errorf("recompute is_blocked after source-repo delete: %w", err)
}
return int(rowsAffected), nil
}View on GitHub (pinned to 71377f2769)
Solutions
- Check the wrapped error and which driver is configured; switch to a driver that supports RowsAffected
- Treat the delete as successful and tolerate a missing count if the count is only informational
- Pin to the standard, supported database driver for bd
Defensive patterns
Strategy: fallback
Validate before calling
// verify driver supports RowsAffected with a trivial statement
res, err := db.Exec("SELECT 1")
_, rerr := res.RowsAffected() // fail fast at startup if unsupported Type guard
var unsupported interface{ Error() string }
_ = errors.As(err, &unsupported) // driver-specific RowsAffected limitation Try / catch
n, err := DeleteIssuesBySourceRepoInTx(ctx, tx, repo)
if err != nil && strings.Contains(err.Error(), "rows affected") {
// deletion succeeded; degrade gracefully by treating the count as unknown
log.Warn("could not read affected-row count", "err", err)
return nil
} Prevention
- Use bd's supported standard driver; avoid middleware that drops RowsAffected
- Treat the count as informational, not transactional
- Add a startup smoke test for driver capability
When it happens
Trigger: RowsAffected returns an error, which is rare and driver-specific: some drivers cannot report affected rows for certain statements or connection states.
Common situations: Using a driver or middleware wrapper that does not implement RowsAffected; exotic storage backends behind the same sql.Tx interface.
Related errors
- failed to check rows affected for issue counter prefix %q: %
- failed to check rows affected after seeding for prefix %q: %
- db: DependencySQLRepository.DeleteAllForIDs rows affected: %
- db: EventsSQLRepository.DeleteAllForIDs rows affected: %w
- db: Update %s: rows affected: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/101e051ae406a512.
Report an issue: GitHub.