gastownhall/beads · error

db: LabelSQLRepository.ListByIssueIDs: rows: %w

Error message

db: LabelSQLRepository.ListByIssueIDs: rows: %w

What it means

LabelSQLRepository.ListByIssueIDs failed after row iteration: rows.Err() reported an error that occurred while fetching rows. The result map is unreliable because streaming was interrupted.

Source

Thrown at internal/storage/domain/db/label.go:184

	q := fmt.Sprintf(
		"SELECT issue_id, label FROM %s WHERE issue_id IN (%s) ORDER BY issue_id, label",
		table, strings.Join(placeholders, ","),
	)
	rows, err := r.runner.QueryContext(ctx, q, args...)
	if err != nil {
		return nil, fmt.Errorf("db: LabelSQLRepository.ListByIssueIDs: %w", err)
	}
	defer rows.Close()

	for rows.Next() {
		var issueID, label string
		if err := rows.Scan(&issueID, &label); err != nil {
			return nil, fmt.Errorf("db: LabelSQLRepository.ListByIssueIDs: scan: %w", err)
		}
		result[issueID] = append(result[issueID], label)
	}
	if err := rows.Err(); err != nil {
		return nil, fmt.Errorf("db: LabelSQLRepository.ListByIssueIDs: rows: %w", err)
	}
	return result, nil
}

func (r *labelSQLRepositoryImpl) DeleteAllForIDs(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"
	}
	total := 0
	for start := 0; start < len(ids); start += deleteBatchSize {
		end := start + deleteBatchSize
		if end > len(ids) {
			end = len(ids)
		}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Unwrap the error for the driver-level cause (context deadline exceeded, connection reset)
  2. Extend caller context timeout or reduce the returned row count by batching issueIDs
  3. Check database server health/logs for aborted connections
  4. Retry the call with a fresh context if the failure was transient

Example fix

// before
ctx := ctx // long-running, possibly expired
m, err := repo.ListByIssueIDs(ctx, ids, opts)
// after
qctx, cancel := context.WithTimeout(ctx, 15*time.Second)
defer cancel()
m, err := repo.ListByIssueIDs(qctx, ids, opts)
Defensive patterns

Strategy: retry

Validate before calling

if len(issueIDs) == 0 { return map[string][]string{}, nil }
if _, ok := ctx.Deadline(); !ok {
    var cancel context.CancelFunc
    ctx, cancel = context.WithTimeout(ctx, 15*time.Second)
    defer cancel()
}

Try / catch

var m map[string][]string
err := retry.Do(3, backoff, func() error {
    var e error
    m, e = repo.ListByIssueIDs(ctx, ids, opts)
    return e
})

Prevention

When it happens

Trigger: Calling ListByIssueIDs when the connection drops, the context is cancelled, or the driver errors while fetching the IN-clause result set.

Common situations: Context deadlines on broad IN queries returning many rows; network issues to a remote database; server-side interruption; embedded database being closed concurrently.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/73aea8b6e32a425d. Report an issue: GitHub.