gastownhall/beads · error

search %s (hydrate): rows: %w

Error message

search %s (hydrate): rows: %w

What it means

searchTablePatternBT wraps the error returned by fetchRows.Err() after the Pattern B batch fetch finished iterating: the driver reported a failure while streaming rows (not a scan error, not an initial query error). This catches mid-result-set failures like dropped connections or backend errors surfaced during row retrieval.

Source

Thrown at internal/storage/issueops/search.go:474

		proj.columns(tables), fetchFrom, strings.Join(placeholders, ","))

	fetchRows, err := tx.QueryContext(ctx, fetchSQL, fetchArgs...)
	if err != nil {
		return nil, fmt.Errorf("search %s (hydrate): %w", tables.Main, err)
	}

	itemMap := make(map[string]T, len(ids))
	for fetchRows.Next() {
		item, scanErr := proj.scan(fetchRows)
		if scanErr != nil {
			_ = fetchRows.Close()
			return nil, fmt.Errorf("search %s (hydrate): scan: %w", tables.Main, scanErr)
		}
		itemMap[proj.id(item)] = item
	}
	_ = fetchRows.Close()
	if err := fetchRows.Err(); err != nil {
		return nil, fmt.Errorf("search %s (hydrate): rows: %w", tables.Main, err)
	}

	// Reorder to preserve the id-scan ORDER BY.
	results := make([]T, 0, len(ids))
	for _, id := range ids {
		if item, ok := itemMap[id]; ok {
			results = append(results, item)
		}
	}

	if proj.hydrate != nil && len(results) > 0 {
		if err := proj.hydrate(ctx, tx, tables, results, filter); err != nil {
			return nil, fmt.Errorf("search %s (pattern B): %w", tables.Main, err)
		}
	}

	return results, nil
}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Read the wrapped rows error; retry the search if it was transient (connection reset, timeout)
  2. Raise the context timeout or remove the deadline for large fetches
  3. Reduce filter.Limit to shrink the batch fetch
  4. Check server logs (Dolt/SQLite) for query aborts or kills around the timestamp
  5. Verify network stability to the database host if using a remote Dolt server

Example fix

// before: short default timeout killed a large batch fetch mid-stream
ctx := context.Background()
// after: bound generously for large result sets
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
rows, err := searchIssues(ctx, tx, q, filter)
Defensive patterns

Strategy: retry

Validate before calling

// pre-check connection health before large batch fetches
if err := tx.PingContext(ctx); err != nil {
    return fmt.Errorf("connection unhealthy before search: %w", err)
}
if ctx.Err() != nil { return ctx.Err() }

Type guard

func isRowsIterationErr(err error) bool {
    return err != nil && strings.Contains(err.Error(), ": rows: ")
}

Try / catch

var res []Issue
var err error
for attempt := 0; attempt < 3; attempt++ {
    res, err = searchIssues(ctx, tx, q, filter)
    if err == nil || !isRowsIterationErr(err) { break }
    time.Sleep(backoff(attempt)) // retry transient mid-stream failures
}
if err != nil { return err }

Prevention

When it happens

Trigger: During iteration of the WHERE id IN (...) fetch, the underlying connection breaks, the server aborts the query, or ctx is cancelled between Next() calls — the driver sets an error on the Rows that only rows.Err() surfaces after Close.

Common situations: Network drop to a remote Dolt server mid-fetch; query killed by a server-side timeout; ctx deadline exceeded on a slow disk; process memory pressure causing driver-level failures.

Related errors


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