gastownhall/beads · error
is_blocked rows from %s: %w
Error message
is_blocked rows from %s: %w
What it means
Wraps rows.Err() after iterating is_blocked rows in readIsBlockedIntoFromTable. Scan can succeed per-row yet the iterator can still fail; this check catches transport/query errors surfaced at the end of iteration (driver disconnect, query killed, server error mid-stream). The library throws it so partial batch results are never returned as if complete.
Source
Thrown at internal/storage/issueops/dependency_queries.go:1053
}
for rows.Next() {
var id string
var b int
if err := rows.Scan(&id, &b); err != nil {
_ = rows.Close()
return fmt.Errorf("scan is_blocked from %s: %w", table, err)
}
// Keep the first-seen (issues) value and skip any later (wisps)
// duplicate, so the batch is_blocked matches per-row IsBlocked.
if seen[id] {
continue
}
seen[id] = true
blocked[id] = b != 0
}
_ = rows.Close()
if err := rows.Err(); err != nil {
return fmt.Errorf("is_blocked rows from %s: %w", table, err)
}
}
return nil
}
// scanDependencyRow scans a single dependency row from a *sql.Rows.
func scanDependencyRow(rows *sql.Rows) (*types.Dependency, error) {
var dep types.Dependency
var createdAt sql.NullTime
var metadata, threadID sql.NullString
if err := rows.Scan(&dep.IssueID, &dep.DependsOnID, &dep.Type, &createdAt, &dep.CreatedBy, &metadata, &threadID); err != nil {
return nil, fmt.Errorf("scan dependency: %w", err)
}
if createdAt.Valid {
dep.CreatedAt = createdAt.Time
}View on GitHub (pinned to 71377f2769)
Solutions
- Retry the operation; rows.Err() here is usually transient (connection or context issue).
- Check context deadlines: increase timeout or pass a context with adequate budget for large batches.
- Verify Dolt server/network stability and connection pool settings.
- Reduce batch size so each query completes well within timeouts.
Example fix
// before: no deadline, fails mid-iteration
blocked, err := ops.IsBlockedBatchInTx(ctx, tx, ids)
// after: bounded, retryable context
ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()
blocked, err := ops.IsBlockedBatchInTx(ctx, tx, ids)
if err != nil { return retry(ctx, ...) } Defensive patterns
Strategy: retry
Validate before calling
if err := ctx.Err(); err != nil {
return fmt.Errorf("context already done before batch is_blocked: %w", err)
}
if err := txPlaceholder.PingContext(ctx); err != nil {
return fmt.Errorf("connection dead before batch: %w", err)
} Type guard
func isTransientRowsErr(err error) bool {
return errors.Is(err, context.DeadlineExceeded) ||
errors.Is(err, context.Canceled) ||
errors.Is(err, driver.ErrBadConn)
} Try / catch
err := ops.IsBlockedBatchInTx(ctx, tx, ids)
for attempt := 0; isTransientRowsErr(err) && attempt < 3; attempt++ {
time.Sleep(backoff(attempt))
err = ops.IsBlockedBatchInTx(ctx, tx, ids)
}
if err != nil { return err } Prevention
- Give batch operations generous, explicit context deadlines.
- Keep batch sizes small so result sets drain quickly.
- Monitor Dolt server health and connection pool saturation.
- Never ignore rows.Err() in your own row loops; treat it as retryable.
When it happens
Trigger: IsBlockedBatchInTx runs, rows iterate normally, but the Dolt connection drops or the query is cancelled/timed out before the result set is fully drained, so rows.Err() is non-nil.
Common situations: Long batch is_blocked queries over flaky connections; context timeout cancelling the query mid-iteration; Dolt server restart during a large batch check.
Related errors
- iter issues: query: %w
- resolve existing wisps for batch delete: %w
- set repo mtime: %w
- clear repo mtime: %w
- failed to claim issue: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/3a090feceb1afad9.
Report an issue: GitHub.