gastownhall/beads · error
search %s (id scan): rows: %w
Error message
search %s (id scan): rows: %w
What it means
Raised when rows.Err() is non-nil after iterating all id rows in scanFilterIDs. As with the full-search variant, this catches errors surfaced during row streaming (connection drop, driver I/O) rather than at query execution.
Source
Thrown at internal/storage/domain/db/issue_search.go:317
idQuery := fmt.Sprintf(`%s%s.id FROM %s %s %s %s`,
selectKw, tables.Main, fromSQL, whereSQL, orderBy, window.sql)
rows, err := r.runner.QueryContext(ctx, idQuery, args...)
if err != nil {
return nil, false, fmt.Errorf("search %s (id scan): %w", tables.Main, err)
}
defer func() { _ = rows.Close() }()
var ids []string
for rows.Next() {
var id string
if err := rows.Scan(&id); err != nil {
return nil, false, fmt.Errorf("search %s (id scan): scan: %w", tables.Main, err)
}
ids = append(ids, id)
}
if err := rows.Err(); err != nil {
return nil, false, fmt.Errorf("search %s (id scan): rows: %w", tables.Main, err)
}
sortRowsGoSide(ids, func(id string) string { return id }, filter.SortBy, filter.SortDesc)
return finishWindow(ids, window)
}
func (r *issueSQLRepositoryImpl) hydrateIssues(ctx context.Context, issues []*types.Issue, tables filterTables, includeDeps bool, skipLabels bool) error {
if len(issues) == 0 {
return nil
}
ids := make([]string, len(issues))
for i, issue := range issues {
ids[i] = issue.ID
}
if !skipLabels {
labelMap, err := r.getLabelsFromTable(ctx, tables.Labels, ids)View on GitHub (pinned to 71377f2769)
Solutions
- Check the wrapped error for connection vs I/O cause and retry the search.
- Move large workloads close to the database (avoid NAS-hosted .beads directories).
- Narrow the filter (status, limit, label) to reduce streamed rows.
- Increase driver timeout/read settings for remote Dolt connections.
Example fix
// before db on NAS path; ids scan drops mid-iteration // after move .beads to local disk or run bd against a local dolt server
Defensive patterns
Strategy: retry
Validate before calling
if err := ctx.Err(); err != nil { return err }
// keep DB on local storage; check network before remote dolt server calls
if err := pingDoltServer(ctx); err != nil { return err } Type guard
func isIDScanRowsError(err error) bool {
return err != nil && strings.Contains(err.Error(), "(id scan): rows: ")
} Try / catch
err := retry.Do(3, backoff, func() error {
_, e := store.Search(ctx, q, filter)
if e != nil && isIDScanRowsError(e) {
return e // transient stream drop
}
return retry.Stop(e)
}) Prevention
- Avoid NAS/network-attached locations for embedded databases.
- Bound streamed id scans with filters or limits.
- Tune driver timeouts for remote connections.
- Prevent system sleep during long-running batch jobs.
When it happens
Trigger: Streaming the id list for a filtered search when the connection dies mid-iteration: network loss to a remote Dolt server, DB process termination, or file I/O failure on an embedded database.
Common situations: Very large issue tables scanned over flaky network connections; embedded SQLite on network-attached storage; laptop sleep / network switch during a long scan.
Related errors
- search %s: rows: %w
- get next child ID: iterate children: %w
- iterate dependency sources: %w
- iterate dependency targets: %w
- count edges in %s: rows: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/d22f049506baa1ca.
Report an issue: GitHub.