gastownhall/beads · error
db: LabelSQLRepository.List: rows: %w
Error message
db: LabelSQLRepository.List: rows: %w
What it means
LabelSQLRepository.List failed at the end of iteration: rows.Err() returned non-nil after all rows were consumed. This indicates the rows stream broke mid-iteration (connection loss, driver error, context cancellation) rather than a per-row conversion failure.
Source
Thrown at internal/storage/domain/db/label.go:148
rows, err := r.runner.QueryContext(ctx,
fmt.Sprintf("SELECT label FROM %s WHERE issue_id = ? ORDER BY label", table),
issueID,
)
if err != nil {
return nil, fmt.Errorf("db: LabelSQLRepository.List %s: %w", issueID, err)
}
defer rows.Close()
var out []string
for rows.Next() {
var label string
if err := rows.Scan(&label); err != nil {
return nil, fmt.Errorf("db: LabelSQLRepository.List: scan: %w", err)
}
out = append(out, label)
}
if err := rows.Err(); err != nil {
return nil, fmt.Errorf("db: LabelSQLRepository.List: rows: %w", err)
}
return out, nil
}
func (r *labelSQLRepositoryImpl) ListByIssueIDs(ctx context.Context, issueIDs []string, opts domain.LabelOpts) (map[string][]string, error) {
result := make(map[string][]string)
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 := pickLabelTable(opts.UseWispsTable)
//nolint:gosec // G201: table is one of two hardcoded constants
q := fmt.Sprintf(View on GitHub (pinned to 71377f2769)
Solutions
- Unwrap the error to see the driver-level cause (context deadline, connection reset, etc.)
- Check caller-side context timeouts: increase the deadline or pass a non-cancelled context
- Verify database connectivity/restart if the connection was dropped
- If datasets are large, paginate or narrow the query instead of streaming all rows in one call
Example fix
// before ctx := context.Background() labels, _ := repo.List(ctx, opts) // after ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() labels, _ := repo.List(ctx, opts)
Defensive patterns
Strategy: try-catch
Validate before calling
// ensure context has sane deadline before call
if _, ok := ctx.Deadline(); !ok {
var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(ctx, 30*time.Second)
defer cancel()
} Try / catch
labels, err := repo.List(ctx, opts)
if err != nil {
var cause error
errors.As(err, &cause)
if errors.Is(err, context.DeadlineExceeded) || isNetErr(cause) {
// retry with backoff
}
return err
} Prevention
- Always pass a context with an appropriate timeout
- Avoid streaming unbounded row sets; add LIMIT/pagination
- Monitor connection health for remote databases
- Do not close the DB handle while queries are in flight
When it happens
Trigger: Calling List when the underlying connection drops or the context is cancelled/times out while rows are still being iterated.
Common situations: Long-running queries over large label sets hitting context deadlines; network interruption to a remote database; embedded database closed mid-query; driver-level errors surfaced only after iteration completes.
Related errors
- db: LabelSQLRepository.ListByIssueIDs: rows: %w
- failed to begin transaction: %w
- failed to recompute is_blocked: %w
- failed to commit is_blocked repairs: %w
- failed to query orphaned dependencies: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/3c1bd29d559a651c.
Report an issue: GitHub.