gastownhall/beads · error
db: RawSQL Query: rows: %w
Error message
db: RawSQL Query: rows: %w
What it means
Wraps the value of rows.Err() after finishing iteration in RawSQLRepository.Query. rows.Err() reports an error that terminated the rows.Next() loop early, meaning the result set was only partially read. It exists because database/sql surfaces driver/network failures during iteration through Err(), not through Scan.
Source
Thrown at internal/storage/domain/db/raw_sql.go:50
result := &domain.RawSQLResult{Columns: columns}
for rows.Next() {
values := make([]any, len(columns))
ptrs := make([]any, len(columns))
for i := range values {
ptrs[i] = &values[i]
}
if err := rows.Scan(ptrs...); err != nil {
return nil, fmt.Errorf("db: RawSQL Query: scan: %w", err)
}
for i, v := range values {
if b, ok := v.([]byte); ok {
values[i] = string(b)
}
}
result.Rows = append(result.Rows, values)
}
if err := rows.Err(); err != nil {
return nil, fmt.Errorf("db: RawSQL Query: rows: %w", err)
}
return result, nil
}
func (r *rawSQLRepositoryImpl) Exec(ctx context.Context, query string, args ...any) (int64, error) {
res, err := r.runner.ExecContext(ctx, query, args...)
if err != nil {
return 0, fmt.Errorf("db: RawSQL Exec: %w", err)
}
affected, err := res.RowsAffected()
if err != nil {
return 0, fmt.Errorf("db: RawSQL Exec: rows affected: %w", err)
}
return affected, nil
}
View on GitHub (pinned to 71377f2769)
Solutions
- Inspect the wrapped error for context deadline/cancellation and increase the timeout or narrow the query
- Add LIMIT/pagination to keep result sets small so iteration finishes before any timeout
- Retry the query on transient network errors
- Verify DB connection liveness/idle timeouts between client and server
Example fix
// before rows, err := repo.Query(ctx, "SELECT id FROM issues") // after: bound the work so iteration completes ctx, cancel := context.WithTimeout(ctx, 30*time.Second) defer cancel() rows, err := repo.Query(ctx, "SELECT id FROM issues LIMIT 1000")
Defensive patterns
Strategy: retry
Validate before calling
// prefer bounded result sets const maxRows = 10000 q := "SELECT id FROM issues LIMIT " + strconv.Itoa(maxRows)
Type guard
func isRowsIterationError(err error) bool {
return err != nil && strings.Contains(err.Error(), "RawSQL Query: rows")
} Try / catch
res, err := repo.Query(ctx, q)
if err != nil && isRowsIterationError(err) {
if errors.Is(err, context.DeadlineExceeded) { /* raise timeout or paginate */ }
// retry once on transient network errors
} Prevention
- Paginate large result sets instead of streaming them unbounded
- Set generous but finite context timeouts
- Monitor connection stability / idle timeouts
- Retry transient network errors idempotently
When it happens
Trigger: Calling RawSQLRepository.Query when the underlying connection is lost or the context is canceled while rows are still being streamed from the server.
Common situations: Long-running raw queries over slow/unstable links; server-side timeouts killing the connection mid-stream; context deadline exceeded while fetching a large result set.
Related errors
- failed to iterate peers for migration: %w
- db: ChildCounterSQLRepository.NextChildID: rows: %w
- db: CommentSQLRepository.CountsByIssueIDs: rows: %w
- db: CommentSQLRepository.ListByIssueIDs: rows: %w
- search union with counts: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/afd39c0968795790.
Report an issue: GitHub.