gastownhall/beads · error

get issues by IDs: label rows: %w

Error message

get issues by IDs: label rows: %w

What it means

Wraps the labelRows.Err() check after iterating hydrated label rows in GetIssuesByIDsInTx. The scan loop completed but the result set hit a driver/connection error at the end of iteration.

Source

Thrown at internal/storage/issueops/dependencies.go:1085

				labelRows, err := tx.QueryContext(ctx, fmt.Sprintf(
					`SELECT issue_id, label FROM %s WHERE issue_id IN (%s) ORDER BY issue_id, label`,
					pair.labelTbl, inClause), args...)
				if err != nil {
					return nil, fmt.Errorf("get issues by IDs: labels from %s: %w", pair.labelTbl, err)
				}
				for labelRows.Next() {
					var issueID, label string
					if scanErr := labelRows.Scan(&issueID, &label); scanErr != nil {
						_ = labelRows.Close()
						return nil, fmt.Errorf("get issues by IDs: scan label: %w", scanErr)
					}
					if issue, ok := issueMap[issueID]; ok {
						issue.Labels = append(issue.Labels, label)
					}
				}
				_ = labelRows.Close()
				if err := labelRows.Err(); err != nil {
					return nil, fmt.Errorf("get issues by IDs: label rows: %w", err)
				}
			}
		}
	}

	return allIssues, nil
}

// GetDependenciesWithMetadataInTx returns issues that the given issueID depends on,
// along with the dependency type. Works within an existing transaction.
// Queries both dependency tables to handle cross-table dependencies.
//
//nolint:gosec // G201: table names come from hardcoded constants
func GetDependenciesWithMetadataInTx(ctx context.Context, tx DBTX, issueID string) ([]*types.IssueWithDependencyMetadata, error) {
	type depMeta struct {
		depID, depType string
	}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Retry — the fetch is read-only and idempotent
  2. Check upstream context cancellation/timeout settings
  3. Investigate network/proxy idle timeouts if this recurs on large sets
Defensive patterns

Strategy: retry

Validate before calling

// Ensure adequate deadline and healthy pool before batch fetches:
ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()
if err := db.PingContext(ctx); err != nil { return err }

Try / catch

issues, err := GetIssuesByIDsInTx(ctx, tx, ids, nil)
if err != nil && strings.Contains(err.Error(), "label rows") {
    if errors.Is(err, context.Canceled) { return err } // don't retry cancels
    if isTransientDBError(err) {
        issues, err = GetIssuesByIDsInTx(ctx, tx, ids, nil) // one retry
    }
}

Prevention

When it happens

Trigger: After consuming all label rows, labelRows.Err() returns non-nil — connection dropped, context canceled, or driver streaming error during iteration.

Common situations: Client timeout canceling the context mid-iteration; unstable connection to the DB; large label result sets iterating longer than the connection allows.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/543dc739858050fe. Report an issue: GitHub.