gastownhall/beads · error
get labels for issues: rows: %w
Error message
get labels for issues: rows: %w
What it means
This error is returned when rows.Err() reports a failure after iterating the batched label rows in getLabelsIntoFromTable. It catches errors that occur mid-stream during iteration (connection loss, context cancellation) after all individual scans succeeded. The library surfaces it so bulk hydration never silently returns an incomplete label map.
Source
Thrown at internal/storage/issueops/labels.go:125
args[i] = id
}
rows, err := tx.QueryContext(ctx, fmt.Sprintf(
`SELECT issue_id, label FROM %s WHERE issue_id IN (%s) ORDER BY issue_id, label`,
labelTable, strings.Join(placeholders, ",")), args...)
if err != nil {
return fmt.Errorf("get labels for issues from %s: %w", labelTable, err)
}
for rows.Next() {
var issueID, label string
if err := rows.Scan(&issueID, &label); err != nil {
_ = rows.Close()
return fmt.Errorf("get labels for issues: scan: %w", err)
}
result[issueID] = append(result[issueID], label)
}
_ = rows.Close()
if err := rows.Err(); err != nil {
return fmt.Errorf("get labels for issues: rows: %w", err)
}
}
return nil
}
// AddLabelInTx adds a label to an issue and records an event within an existing
// transaction. Automatically routes to wisp tables if the ID is an active wisp.
// Uses INSERT IGNORE for idempotency.
func AddLabelInTx(ctx context.Context, tx DBTX, labelTable, eventTable, issueID, label, actor string) error {
// Reject an over-length label up front. The INSERT IGNORE below would
// otherwise silently truncate it to the VARCHAR(255) column, storing a label
// the caller never sent; a typed ErrFieldTooLong is the clean rejection.
if err := types.CheckFieldLen("label", label); err != nil {
return err
}
if labelTable == "" || eventTable == "" {
isWisp := IsActiveWispInTx(ctx, tx, issueID)
_, lt, et, _ := WispTableRouting(isWisp)View on GitHub (pinned to 71377f2769)
Solutions
- Increase the context timeout for bulk hydration calls
- Reduce batch sizes to shorten each query's runtime
- Retry the operation after confirming connection health
- Check the wrapped error for context.DeadlineExceeded and scale timeouts accordingly
Defensive patterns
Strategy: retry
Validate before calling
if err := ctx.Err(); err != nil { return fmt.Errorf("context done before bulk label fetch: %w", err) } Try / catch
m, err := issueops.GetLabelsForIssuesInTx(ctx, tx, ids)
if err != nil {
if errors.Is(err, context.DeadlineExceeded) {
ctx, cancel = context.WithTimeout(context.Background(), longerTimeout)
defer cancel()
// retry with extended deadline and/or smaller batches
}
return err
} Prevention
- Size batches so each query completes well within the deadline
- Use the optional precomputed wisp-set parameter when hydrating multiple batches in one tx
- Apply retries with exponential backoff for remote Dolt backends
- Monitor context-deadline errors as a latency signal
When it happens
Trigger: GetLabelsForIssuesInTx batch iteration interrupted by connection drops or context deadline expiry before rows are fully consumed.
Common situations: Remote Dolt latency causing context timeouts on large batches (see GH#3414); network instability; server failover mid-query.
Related errors
- failed to iterate existing issues for prefix %q: %w
- failed to begin transaction: %w
- failed to get wisp labels: %w
- %s close timed out after %v
- db: ChildCounterSQLRepository.NextChildID: rows: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/0bf46abfdeed351a.
Report an issue: GitHub.