gastownhall/beads · error
get blocking info: blocked-by rows: %w
Error message
get blocking info: blocked-by rows: %w
What it means
Returned by queryBlockedByInfo when rows.Err() reports a driver failure after iterating the blocked-by result set — the connection or query failed mid-stream rather than any individual row failing to scan.
Source
Thrown at internal/storage/issueops/dependency_queries.go:634
if optionalBlockedTable(depTable) && isTableNotExistError(err) {
continue
}
return fmt.Errorf("get blocked-by info from %s: %w", depTable, err)
}
var depRows []blockingInfoRow
var blockerIDs []string
for rows.Next() {
var row blockingInfoRow
if scanErr := rows.Scan(&row.issueID, &row.blockerID, &row.depType); scanErr != nil {
_ = rows.Close()
return fmt.Errorf("get blocking info: scan blocked-by: %w", scanErr)
}
depRows = append(depRows, row)
blockerIDs = append(blockerIDs, row.blockerID)
}
_ = rows.Close()
if err := rows.Err(); err != nil {
return fmt.Errorf("get blocking info: blocked-by rows: %w", err)
}
statusByID, err := loadStatusByIDInTx(ctx, tx, blockerIDs)
if err != nil {
return fmt.Errorf("get blocking info: blocker status: %w", err)
}
for _, row := range depRows {
if statusByID[row.blockerID] == types.StatusClosed {
continue
}
if row.depType == "parent-child" {
parentMap[row.issueID] = row.blockerID
} else {
blockedByMap[row.issueID] = append(blockedByMap[row.issueID], row.blockerID)
}
}
}
View on GitHub (pinned to 71377f2769)
Solutions
- Read the wrapped error: for context deadline/cancellation, increase timeouts or shrink input batches.
- Retry the operation; transient stream errors usually resolve.
- Check remote Dolt server health and logs; restart if it reset connections.
- Reduce the number of issue IDs per call to shorten result streams.
- Raise proxy/LB idle timeouts if long queries are being cut off.
Example fix
// before: unbounded context on a slow remote
info, err := GetBlockingInfoForIssuesInTx(ctx, tx, manyIDs)
// after: explicit timeout with retry
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
info, err := GetBlockingInfoForIssuesInTx(ctx, tx, manyIDs)
if err != nil && isTransient(err) {
info, err = GetBlockingInfoForIssuesInTx(ctx, tx, manyIDs) // retry
} Defensive patterns
Strategy: retry
Validate before calling
// Go: fail fast if the connection is already dead
if err := tx.PingContext(ctx); err != nil {
return fmt.Errorf("skipping blocked-by query, DB unreachable: %w", err)
} Type guard
func isBlockedByRowsError(err error) bool {
return err != nil && strings.Contains(err.Error(), "blocked-by rows")
} Try / catch
blockedBy, blocks, parents, err := GetBlockingInfoForIssuesInTx(ctx, tx, ids)
if isBlockedByRowsError(err) && errors.Is(err, context.DeadlineExceeded) {
ctx2, cancel := context.WithTimeout(context.Background(), longerTimeout)
defer cancel()
blockedBy, blocks, parents, err = GetBlockingInfoForIssuesInTx(ctx2, tx, ids)
} Prevention
- Use contexts with adequate deadlines for remote backends.
- Keep batch sizes moderate to keep result streams short.
- Enable TCP keepalives on the DB connection.
- Retry transient errors with jittered exponential backoff.
- Monitor server logs for mid-query disconnects.
When it happens
Trigger: Calling GetBlockingInfoForIssuesInTx when the database connection drops, the context is cancelled, or the remote Dolt server errors while the blocked-by rows are being streamed.
Common situations: Flaky network to remote Dolt; context deadlines on large batches; server restarts or idle-connection kills by proxies during bd operations.
Related errors
- get dependency counts: blocker rows: %w
- get dependency records: rows: %w
- get dependency counts: dependent rows: %w
- row iteration error: %w
- dolt server connection failed: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/4ffcf5af68043206.
Report an issue: GitHub.