{"record":{"id":"73aea8b6e32a425d","repo":"gastownhall/beads","slug":"db-labelsqlrepository-listbyissueids-rows-w","errorCode":null,"errorMessage":"db: LabelSQLRepository.ListByIssueIDs: rows: %w","messagePattern":"db: LabelSQLRepository\\.ListByIssueIDs: rows: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/domain/db/label.go","lineNumber":184,"sourceCode":"\tq := fmt.Sprintf(\n\t\t\"SELECT issue_id, label FROM %s WHERE issue_id IN (%s) ORDER BY issue_id, label\",\n\t\ttable, strings.Join(placeholders, \",\"),\n\t)\n\trows, err := r.runner.QueryContext(ctx, q, args...)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"db: LabelSQLRepository.ListByIssueIDs: %w\", err)\n\t}\n\tdefer rows.Close()\n\n\tfor rows.Next() {\n\t\tvar issueID, label string\n\t\tif err := rows.Scan(&issueID, &label); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"db: LabelSQLRepository.ListByIssueIDs: scan: %w\", err)\n\t\t}\n\t\tresult[issueID] = append(result[issueID], label)\n\t}\n\tif err := rows.Err(); err != nil {\n\t\treturn nil, fmt.Errorf(\"db: LabelSQLRepository.ListByIssueIDs: rows: %w\", err)\n\t}\n\treturn result, nil\n}\n\nfunc (r *labelSQLRepositoryImpl) DeleteAllForIDs(ctx context.Context, ids []string, opts domain.LabelOpts) (int, error) {\n\tif len(ids) == 0 {\n\t\treturn 0, nil\n\t}\n\ttable := \"labels\"\n\tif opts.UseWispsTable {\n\t\ttable = \"wisp_labels\"\n\t}\n\ttotal := 0\n\tfor start := 0; start < len(ids); start += deleteBatchSize {\n\t\tend := start + deleteBatchSize\n\t\tif end > len(ids) {\n\t\t\tend = len(ids)\n\t\t}","sourceCodeStart":166,"sourceCodeEnd":202,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/domain/db/label.go#L166-L202","documentation":"LabelSQLRepository.ListByIssueIDs failed after row iteration: rows.Err() reported an error that occurred while fetching rows. The result map is unreliable because streaming was interrupted.","triggerScenarios":"Calling ListByIssueIDs when the connection drops, the context is cancelled, or the driver errors while fetching the IN-clause result set.","commonSituations":"Context deadlines on broad IN queries returning many rows; network issues to a remote database; server-side interruption; embedded database being closed concurrently.","solutions":["Unwrap the error for the driver-level cause (context deadline exceeded, connection reset)","Extend caller context timeout or reduce the returned row count by batching issueIDs","Check database server health/logs for aborted connections","Retry the call with a fresh context if the failure was transient"],"exampleFix":"// before\nctx := ctx // long-running, possibly expired\nm, err := repo.ListByIssueIDs(ctx, ids, opts)\n// after\nqctx, cancel := context.WithTimeout(ctx, 15*time.Second)\ndefer cancel()\nm, err := repo.ListByIssueIDs(qctx, ids, opts)","handlingStrategy":"retry","validationCode":"if len(issueIDs) == 0 { return map[string][]string{}, nil }\nif _, ok := ctx.Deadline(); !ok {\n    var cancel context.CancelFunc\n    ctx, cancel = context.WithTimeout(ctx, 15*time.Second)\n    defer cancel()\n}","typeGuard":null,"tryCatchPattern":"var m map[string][]string\nerr := retry.Do(3, backoff, func() error {\n    var e error\n    m, e = repo.ListByIssueIDs(ctx, ids, opts)\n    return e\n})","preventionTips":["Retry transient iteration errors with backoff","Bound result set size via batching of issueIDs","Keep context deadlines proportional to expected row counts","Verify network stability for remote databases"],"tags":["go","database","sql","iteration"],"backgroundTag":"sql-rows-iteration-error","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}