{"record":{"id":"0bf46abfdeed351a","repo":"gastownhall/beads","slug":"get-labels-for-issues-rows-w","errorCode":null,"errorMessage":"get labels for issues: rows: %w","messagePattern":"get labels for issues: rows: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/labels.go","lineNumber":125,"sourceCode":"\t\t\targs[i] = id\n\t\t}\n\t\trows, err := tx.QueryContext(ctx, fmt.Sprintf(\n\t\t\t`SELECT issue_id, label FROM %s WHERE issue_id IN (%s) ORDER BY issue_id, label`,\n\t\t\tlabelTable, strings.Join(placeholders, \",\")), args...)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"get labels for issues from %s: %w\", labelTable, err)\n\t\t}\n\t\tfor rows.Next() {\n\t\t\tvar issueID, label string\n\t\t\tif err := rows.Scan(&issueID, &label); err != nil {\n\t\t\t\t_ = rows.Close()\n\t\t\t\treturn fmt.Errorf(\"get labels for issues: scan: %w\", err)\n\t\t\t}\n\t\t\tresult[issueID] = append(result[issueID], label)\n\t\t}\n\t\t_ = rows.Close()\n\t\tif err := rows.Err(); err != nil {\n\t\t\treturn fmt.Errorf(\"get labels for issues: rows: %w\", err)\n\t\t}\n\t}\n\treturn nil\n}\n\n// AddLabelInTx adds a label to an issue and records an event within an existing\n// transaction. Automatically routes to wisp tables if the ID is an active wisp.\n// Uses INSERT IGNORE for idempotency.\nfunc AddLabelInTx(ctx context.Context, tx DBTX, labelTable, eventTable, issueID, label, actor string) error {\n\t// Reject an over-length label up front. The INSERT IGNORE below would\n\t// otherwise silently truncate it to the VARCHAR(255) column, storing a label\n\t// the caller never sent; a typed ErrFieldTooLong is the clean rejection.\n\tif err := types.CheckFieldLen(\"label\", label); err != nil {\n\t\treturn err\n\t}\n\tif labelTable == \"\" || eventTable == \"\" {\n\t\tisWisp := IsActiveWispInTx(ctx, tx, issueID)\n\t\t_, lt, et, _ := WispTableRouting(isWisp)","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/labels.go#L107-L143","documentation":"This error is returned when rows.Err() reports a failure after iterating the batched label rows in getLabelsIntoFromTable. It catches errors that occur mid-stream during iteration (connection loss, context cancellation) after all individual scans succeeded. The library surfaces it so bulk hydration never silently returns an incomplete label map.","triggerScenarios":"GetLabelsForIssuesInTx batch iteration interrupted by connection drops or context deadline expiry before rows are fully consumed.","commonSituations":"Remote Dolt latency causing context timeouts on large batches (see GH#3414); network instability; server failover mid-query.","solutions":["Increase the context timeout for bulk hydration calls","Reduce batch sizes to shorten each query's runtime","Retry the operation after confirming connection health","Check the wrapped error for context.DeadlineExceeded and scale timeouts accordingly"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"if err := ctx.Err(); err != nil { return fmt.Errorf(\"context done before bulk label fetch: %w\", err) }","typeGuard":null,"tryCatchPattern":"m, err := issueops.GetLabelsForIssuesInTx(ctx, tx, ids)\nif err != nil {\n    if errors.Is(err, context.DeadlineExceeded) {\n        ctx, cancel = context.WithTimeout(context.Background(), longerTimeout)\n        defer cancel()\n        // retry with extended deadline and/or smaller batches\n    }\n    return err\n}","preventionTips":["Size batches so each query completes well within the deadline","Use the optional precomputed wisp-set parameter when hydrating multiple batches in one tx","Apply retries with exponential backoff for remote Dolt backends","Monitor context-deadline errors as a latency signal"],"tags":["database","rows-iteration","labels","timeout"],"backgroundTag":"rows-iteration-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}