gastownhall/beads · error

wisp id set: rows: %w

Error message

wisp id set: rows: %w

What it means

WispIDSetInTx issues a batched `SELECT id FROM wisps WHERE id IN (...)` and calls rows.Err() after draining each batch. This error wraps a rows-iteration failure (connection drop, context cancellation mid-scan, driver decode error) after rows were successfully opened but the iteration itself reported an error via rows.Err(). It means the wisp-ID set could not be built reliably, so the caller must not trust a partial partition.

Source

Thrown at internal/storage/issueops/wisp_routing.go:104

			placeholders[i] = "?"
			args[i] = id
		}
		q := fmt.Sprintf("SELECT id FROM wisps WHERE id IN (%s)", strings.Join(placeholders, ","))
		rows, err := tx.QueryContext(ctx, q, args...)
		if err != nil {
			return nil, fmt.Errorf("wisp id set: %w", err)
		}
		for rows.Next() {
			var id string
			if err := rows.Scan(&id); err != nil {
				_ = rows.Close()
				return nil, fmt.Errorf("wisp id set: scan: %w", err)
			}
			set[id] = struct{}{}
		}
		_ = rows.Close()
		if err := rows.Err(); err != nil {
			return nil, fmt.Errorf("wisp id set: rows: %w", err)
		}
	}
	return set, nil
}

// partitionByWispSet splits ids into (wispIDs, permIDs) using the provided
// wisp-id set. If wispSet is nil the caller must populate it first via
// WispIDSetInTx; this helper does no I/O.
func partitionByWispSet(ids []string, wispSet map[string]struct{}) (wispIDs, permIDs []string) {
	for _, id := range ids {
		if _, isWisp := wispSet[id]; isWisp {
			wispIDs = append(wispIDs, id)
		} else {
			permIDs = append(permIDs, id)
		}
	}
	return wispIDs, permIDs
}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Check the wrapped driver error to determine root cause: network error → reconnect; context.DeadlineExceeded → raise the timeout or reduce the batch size
  2. Retry the operation with a fresh transaction — Dolt MVCC makes the set consistent per tx, so a clean retry is safe
  3. Verify connectivity to the Dolt server (bd dolt ping / connection settings) if errors are persistent
  4. Reduce queryBatchSize input volume so each IN-query chunk completes well inside the context deadline

Example fix

// before
set, err := issueops.WispIDSetInTx(ctx, tx, ids)
if err != nil { return err }
// after
ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()
set, err := issueops.WispIDSetInTx(ctx, tx, ids)
if err != nil {
	if errors.Is(err, context.DeadlineExceeded) { return retryWithFreshTx(ctx, ids) }
	return fmt.Errorf("partition wisps: %w", err)
}
Defensive patterns

Strategy: retry

Validate before calling

if len(ids) == 0 { return nil } // never triggers a query
if err := ctx.Err(); err != nil { return fmt.Errorf("context already done: %w", err) }

Try / catch

set, err := issueops.WispIDSetInTx(ctx, tx, ids)
if err != nil {
	var netErr net.Error
	if errors.As(err, &netErr) || errors.Is(err, context.DeadlineExceeded) {
		// retry with fresh tx and larger deadline
	}
	return err
}

Prevention

When it happens

Trigger: Calling WispIDSetInTx (directly or via ReconcileChildCounters, DeleteInTx, GetIssuesByIDsInTx, ExecuteAddDependencies) when the underlying database connection fails or the context is cancelled while iterating result rows of the wisps-table IN query.

Common situations: Dolt server connection dropped mid-query (network blip to remote Dolt); caller's context deadline exceeded during a large batch partition (GH#3414 WAN-latency scenario); driver-level row decode failure after schema drift.

Related errors


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