{"record":{"id":"03fd6187a24cd05a","repo":"gastownhall/beads","slug":"get-issues-by-ids-rows-w","errorCode":null,"errorMessage":"get issues by IDs: rows: %w","messagePattern":"get issues by IDs: rows: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/dependencies.go","lineNumber":1062,"sourceCode":"\t\t\trows, err := tx.QueryContext(ctx, fmt.Sprintf(\n\t\t\t\t`SELECT %s FROM %s %s WHERE id IN (%s)`,\n\t\t\t\tIssueSelectColumns, pair.table, sqlbuild.LeaseJoin(pair.table), inClause), args...)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"get issues by IDs from %s: %w\", pair.table, err)\n\t\t\t}\n\t\t\tissueMap := make(map[string]*types.Issue)\n\t\t\tfor rows.Next() {\n\t\t\t\tissue, scanErr := ScanIssueFrom(rows)\n\t\t\t\tif scanErr != nil {\n\t\t\t\t\t_ = rows.Close()\n\t\t\t\t\treturn nil, fmt.Errorf(\"get issues by IDs: scan: %w\", scanErr)\n\t\t\t\t}\n\t\t\t\tallIssues = append(allIssues, issue)\n\t\t\t\tissueMap[issue.ID] = issue\n\t\t\t}\n\t\t\t_ = rows.Close()\n\t\t\tif err := rows.Err(); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"get issues by IDs: rows: %w\", err)\n\t\t\t}\n\n\t\t\t// Hydrate labels.\n\t\t\tif len(issueMap) > 0 {\n\t\t\t\tlabelRows, err := tx.QueryContext(ctx, fmt.Sprintf(\n\t\t\t\t\t`SELECT issue_id, label FROM %s WHERE issue_id IN (%s) ORDER BY issue_id, label`,\n\t\t\t\t\tpair.labelTbl, inClause), args...)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"get issues by IDs: labels from %s: %w\", pair.labelTbl, err)\n\t\t\t\t}\n\t\t\t\tfor labelRows.Next() {\n\t\t\t\t\tvar issueID, label string\n\t\t\t\t\tif scanErr := labelRows.Scan(&issueID, &label); scanErr != nil {\n\t\t\t\t\t\t_ = labelRows.Close()\n\t\t\t\t\t\treturn nil, fmt.Errorf(\"get issues by IDs: scan label: %w\", scanErr)\n\t\t\t\t\t}\n\t\t\t\t\tif issue, ok := issueMap[issueID]; ok {\n\t\t\t\t\t\tissue.Labels = append(issue.Labels, label)","sourceCodeStart":1044,"sourceCodeEnd":1080,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/dependencies.go#L1044-L1080","documentation":"Wraps the rows.Err() check after iterating the ID-batch result set in GetIssuesByIDsInTx. It indicates the row iteration itself failed (driver/connection error mid-stream) rather than a scan problem.","triggerScenarios":"After consuming all rows from the `WHERE id IN (...)` SELECT, rows.Err() is non-nil — typically a dropped connection, context cancellation, or driver-level streaming failure during iteration.","commonSituations":"Long-running iteration over a large result set while the connection dies; request context canceled (client timeout) mid-query; network instability to the database.","solutions":["Retry the operation if the cause is a transient connection error","Check for context cancellation upstream and raise the caller's timeout if too short","Investigate network stability / DB proxy idle timeouts for large result sets","Keep transactions short so they don't outlive connection lifetimes"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Ensure the context has adequate deadline before long batch fetches:\nctx, cancel := context.WithTimeout(ctx, 30*time.Second)\ndefer cancel()\n// Ensure connection pool health before large reads:\nif err := db.PingContext(ctx); err != nil { return err }","typeGuard":null,"tryCatchPattern":"issues, err := GetIssuesByIDsInTx(ctx, tx, ids, nil)\nif err != nil && strings.Contains(err.Error(), \"get issues by IDs: rows\") {\n    if errors.Is(err, context.Canceled) {\n        return fmt.Errorf(\"caller canceled; raise timeout: %w\", err)\n    }\n    if isTransientDBError(err) {\n        issues, err = GetIssuesByIDsInTx(ctx, tx, ids, nil) // retry once\n    }\n}","preventionTips":["Give batch fetches generous context deadlines","Keep result sets bounded (reasonable ID-list sizes)","Harden network path to DB (proxy idle timeouts > query time)","Distinguish context.Canceled from transient DB errors before retrying"],"tags":["database","sql","go"],"backgroundTag":"rows-iteration-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}