gastownhall/beads · error
db: CommentSQLRepository.CountsByIssueIDs: rows: %w
Error message
db: CommentSQLRepository.CountsByIssueIDs: rows: %w
What it means
CountsByIssueIDs checks rows.Err() after the scan loop; this error wraps any error encountered while streaming rows (network drop, query canceled, server-side abort). The partial counts map is discarded and a nil map with the error is returned, so callers must not trust partial results.
Source
Thrown at internal/storage/domain/db/comment.go:64
"SELECT issue_id, COUNT(*) FROM %s WHERE issue_id IN (%s) GROUP BY issue_id",
table, strings.Join(placeholders, ","),
)
rows, err := r.runner.QueryContext(ctx, q, args...)
if err != nil {
return nil, fmt.Errorf("db: CommentSQLRepository.CountsByIssueIDs: %w", err)
}
defer rows.Close()
for rows.Next() {
var issueID string
var count int
if err := rows.Scan(&issueID, &count); err != nil {
return nil, fmt.Errorf("db: CommentSQLRepository.CountsByIssueIDs: scan: %w", err)
}
result[issueID] = count
}
if err := rows.Err(); err != nil {
return nil, fmt.Errorf("db: CommentSQLRepository.CountsByIssueIDs: rows: %w", err)
}
return result, nil
}
func (r *commentSQLRepositoryImpl) ListByIssueIDs(ctx context.Context, issueIDs []string, opts domain.CommentOpts) (map[string][]*types.Comment, error) {
result := make(map[string][]*types.Comment)
if len(issueIDs) == 0 {
return result, nil
}
placeholders := make([]string, len(issueIDs))
args := make([]any, len(issueIDs))
for i, id := range issueIDs {
placeholders[i] = "?"
args[i] = id
}
table := pickCommentTable(opts.UseWispsTable)
//nolint:gosec // G201: table is one of two hardcoded constants
q := fmt.Sprintf(`View on GitHub (pinned to 71377f2769)
Solutions
- Inspect the wrapped error: context.Canceled/DeadlineExceeded means raise the timeout or fix the cancelation source.
- Retry the query; it is read-only and idempotent.
- Check network stability and connection pool health (max lifetime vs server wait_timeout).
- For large ID lists, chunk the IN clause to shorten query duration.
Example fix
// before: request context expires mid-query ctx := r.Context() // request-scoped, may be too short // after: detached context with explicit budget for batch reads ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel()
Defensive patterns
Strategy: retry
Validate before calling
if err := ctx.Err(); err != nil { return err } // bail early on dead context Type guard
func isCountRowsError(err error) bool {
return err != nil && strings.Contains(err.Error(), "CountsByIssueIDs: rows:")
} Try / catch
counts, err := repo.CountsByIssueIDs(ctx, ids, opts)
for retry := 0; err != nil && isCountRowsError(err) && retry < 3; retry++ {
time.Sleep(backoff(retry))
counts, err = repo.CountsByIssueIDs(ctx, ids, opts)
} Prevention
- Set explicit deadlines larger than expected query time
- Chunk large ID lists to shorten queries
- Keep connection MaxLifetime under server wait_timeout
When it happens
Trigger: Calling CountsByIssueIDs when the connection drops or the context is canceled while the grouped-count result set is being streamed.
Common situations: HTTP request deadlines canceling mid-query; flaky network to a remote Dolt server; server kill of long-running queries.
Related errors
- db: ChildCounterSQLRepository.NextChildID: rows: %w
- db: CommentSQLRepository.ListByIssueIDs: rows: %w
- get dependencies: rows from %s: %w
- get dependents: rows from %s: %w
- failed to begin transaction: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/20afc27430341f4a.
Report an issue: GitHub.