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

  1. Increase the context timeout for bulk hydration calls
  2. Reduce batch sizes to shorten each query's runtime
  3. Retry the operation after confirming connection health
  4. 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

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


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