{"record":{"id":"afd39c0968795790","repo":"gastownhall/beads","slug":"db-rawsql-query-rows-w","errorCode":null,"errorMessage":"db: RawSQL Query: rows: %w","messagePattern":"db: RawSQL Query: rows: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/domain/db/raw_sql.go","lineNumber":50,"sourceCode":"\tresult := &domain.RawSQLResult{Columns: columns}\n\tfor rows.Next() {\n\t\tvalues := make([]any, len(columns))\n\t\tptrs := make([]any, len(columns))\n\t\tfor i := range values {\n\t\t\tptrs[i] = &values[i]\n\t\t}\n\t\tif err := rows.Scan(ptrs...); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"db: RawSQL Query: scan: %w\", err)\n\t\t}\n\t\tfor i, v := range values {\n\t\t\tif b, ok := v.([]byte); ok {\n\t\t\t\tvalues[i] = string(b)\n\t\t\t}\n\t\t}\n\t\tresult.Rows = append(result.Rows, values)\n\t}\n\tif err := rows.Err(); err != nil {\n\t\treturn nil, fmt.Errorf(\"db: RawSQL Query: rows: %w\", err)\n\t}\n\treturn result, nil\n}\n\nfunc (r *rawSQLRepositoryImpl) Exec(ctx context.Context, query string, args ...any) (int64, error) {\n\tres, err := r.runner.ExecContext(ctx, query, args...)\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"db: RawSQL Exec: %w\", err)\n\t}\n\taffected, err := res.RowsAffected()\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"db: RawSQL Exec: rows affected: %w\", err)\n\t}\n\treturn affected, nil\n}\n","sourceCodeStart":32,"sourceCodeEnd":66,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/domain/db/raw_sql.go#L32-L66","documentation":"Wraps the value of rows.Err() after finishing iteration in RawSQLRepository.Query. rows.Err() reports an error that terminated the rows.Next() loop early, meaning the result set was only partially read. It exists because database/sql surfaces driver/network failures during iteration through Err(), not through Scan.","triggerScenarios":"Calling RawSQLRepository.Query when the underlying connection is lost or the context is canceled while rows are still being streamed from the server.","commonSituations":"Long-running raw queries over slow/unstable links; server-side timeouts killing the connection mid-stream; context deadline exceeded while fetching a large result set.","solutions":["Inspect the wrapped error for context deadline/cancellation and increase the timeout or narrow the query","Add LIMIT/pagination to keep result sets small so iteration finishes before any timeout","Retry the query on transient network errors","Verify DB connection liveness/idle timeouts between client and server"],"exampleFix":"// before\nrows, err := repo.Query(ctx, \"SELECT id FROM issues\")\n// after: bound the work so iteration completes\nctx, cancel := context.WithTimeout(ctx, 30*time.Second)\ndefer cancel()\nrows, err := repo.Query(ctx, \"SELECT id FROM issues LIMIT 1000\")","handlingStrategy":"retry","validationCode":"// prefer bounded result sets\nconst maxRows = 10000\nq := \"SELECT id FROM issues LIMIT \" + strconv.Itoa(maxRows)","typeGuard":"func isRowsIterationError(err error) bool {\n\treturn err != nil && strings.Contains(err.Error(), \"RawSQL Query: rows\")\n}","tryCatchPattern":"res, err := repo.Query(ctx, q)\nif err != nil && isRowsIterationError(err) {\n\tif errors.Is(err, context.DeadlineExceeded) { /* raise timeout or paginate */ }\n\t// retry once on transient network errors\n}","preventionTips":["Paginate large result sets instead of streaming them unbounded","Set generous but finite context timeouts","Monitor connection stability / idle timeouts","Retry transient network errors idempotently"],"tags":["database","sql","rows-iteration","network"],"backgroundTag":"rows-iteration-error","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}