{"record":{"id":"3c9ca1f2a6e70f78","repo":"gastownhall/beads","slug":"search-s-rows-w","errorCode":null,"errorMessage":"search %s: rows: %w","messagePattern":"search (.+?): rows: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/domain/db/issue_search.go","lineNumber":279,"sourceCode":"\t}\n\n\tvar issues []*types.Issue\n\tseen := make(map[string]bool)\n\tfor rows.Next() {\n\t\tissue, scanErr := scanIssue(rows)\n\t\tif scanErr != nil {\n\t\t\t_ = rows.Close()\n\t\t\treturn domain.SearchPage{}, fmt.Errorf(\"search %s: scan: %w\", tables.Main, scanErr)\n\t\t}\n\t\tif seen[issue.ID] {\n\t\t\tcontinue\n\t\t}\n\t\tseen[issue.ID] = true\n\t\tissues = append(issues, issue)\n\t}\n\t_ = rows.Close()\n\tif err := rows.Err(); err != nil {\n\t\treturn domain.SearchPage{}, fmt.Errorf(\"search %s: rows: %w\", tables.Main, err)\n\t}\n\n\tsortRowsGoSide(issues, func(i *types.Issue) string { return i.ID }, filter.SortBy, filter.SortDesc)\n\titems, hasMore, err := finishWindow(issues, window)\n\tif err != nil {\n\t\treturn domain.SearchPage{}, err\n\t}\n\n\tif err := r.hydrateIssues(ctx, items, tables, filter.IncludeDependencies, filter.SkipLabels); err != nil {\n\t\treturn domain.SearchPage{}, fmt.Errorf(\"search %s: hydrate: %w\", tables.Main, err)\n\t}\n\n\treturn domain.SearchPage{Items: items, HasMore: hasMore}, nil\n}\n\nfunc (r *issueSQLRepositoryImpl) scanFilterIDs(ctx context.Context, selectKw, fromSQL, whereSQL string, args []any, filter types.IssueFilter, tables filterTables) ([]string, bool, error) {\n\torderBy := orderBySQL(filter.SortBy, filter.SortDesc, tables.Main)\n\twindow := searchWindowForFilter(filter)","sourceCodeStart":261,"sourceCodeEnd":297,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/domain/db/issue_search.go#L261-L297","documentation":"Raised when rows.Err() returns non-nil after fully iterating the search result set. This is the idiomatic database/sql check for errors that occurred asynchronously during streaming — typically the connection dropping or the server aborting mid-iteration, not an error at query start.","triggerScenarios":"Iterating a large search result when the underlying connection is lost, the driver hits I/O failure reading the next batch, or the database process is killed while rows are still open.","commonSituations":"Searching very large issue sets over a remote Dolt server whose connection times out mid-stream; SQLite file unmounted or network filesystem dropped during iteration; OOM-killer terminating the DB process during a big search.","solutions":["Inspect the wrapped error to distinguish connection loss from driver I/O failure.","Retry the search; transient connection drops usually succeed on a second attempt.","Reduce result-set size with a tighter IssueFilter (limit/status filters) so iteration completes before timeout.","For remote Dolt, increase connection idle/read timeouts in the driver configuration."],"exampleFix":"// before\npage, err := store.Search(ctx, q, types.IssueFilter{}) // huge result set, drops mid-stream\n// after\npage, err := store.Search(ctx, q, types.IssueFilter{Status: \"open\", Limit: 100})","handlingStrategy":"retry","validationCode":"if err := ctx.Err(); err != nil { return err } // ensure context is still live before searching\n// prefer filtered queries over unbounded scans","typeGuard":"func isRowsIterationError(err error) bool {\n\treturn err != nil && strings.Contains(err.Error(), \": rows: \")\n}","tryCatchPattern":"var page domain.SearchPage\nerr := retry.Do(3, backoff, func() error {\n\tvar e error\n\tpage, e = store.Search(ctx, q, filter)\n\tif e != nil && isRowsIterationError(e) {\n\t\treturn e // transient stream failure; retry\n\t}\n\treturn retry.Stop(e)\n})","preventionTips":["Use Limit/status filters so result streams stay small.","Increase connection read/idle timeouts for remote Dolt servers.","Keep the database on reliable local storage.","Retry transient stream errors with bounded backoff."],"tags":["database","sql","connection","streaming"],"backgroundTag":"rows-iteration-error","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}