gastownhall/beads · error

remaining blocker rows from %s: %w

Error message

remaining blocker rows from %s: %w

What it means

Wraps an error from depRows.Err() after iterating the remaining-blocker result set in GetNewlyUnblockedByCloseInTx. This catches errors that surfaced asynchronously during row streaming (connection drop, driver I/O failure) rather than at query or scan time. It fails the unblock computation to avoid returning a partially computed result.

Source

Thrown at internal/storage/issueops/dependency_queries.go:863

			`, DepTargetExpr, depTable, placeholders, DepTargetExpr), append(batchArgs, closedIssueID)...)
			if err != nil {
				if optionalBlockedTable(depTable) && isTableNotExistError(err) {
					continue
				}
				return nil, fmt.Errorf("check remaining blockers from %s: %w", depTable, err)
			}
			for depRows.Next() {
				var candidateID, blockerID string
				if err := depRows.Scan(&candidateID, &blockerID); err != nil {
					_ = depRows.Close()
					return nil, fmt.Errorf("scan remaining blocker: %w", err)
				}
				remainingByCandidate[candidateID] = append(remainingByCandidate[candidateID], blockerID)
				remainingBlockerSet[blockerID] = struct{}{}
			}
			_ = depRows.Close()
			if err := depRows.Err(); err != nil {
				return nil, fmt.Errorf("remaining blocker rows from %s: %w", depTable, err)
			}
		}

		remainingBlockerIDs := make([]string, 0, len(remainingBlockerSet))
		for blockerID := range remainingBlockerSet {
			remainingBlockerIDs = append(remainingBlockerIDs, blockerID)
		}
		sort.Strings(remainingBlockerIDs)
		statusByID, err := loadStatusByIDInTx(ctx, tx, remainingBlockerIDs)
		if err != nil {
			return nil, fmt.Errorf("check remaining blocker status: %w", err)
		}
		for candidateID, blockerIDs := range remainingByCandidate {
			for _, blockerID := range blockerIDs {
				status, ok := statusByID[blockerID]
				if ok && status != types.StatusClosed && status != types.StatusPinned {
					stillBlocked[candidateID] = true
					break

View on GitHub (pinned to 71377f2769)

Solutions

  1. Check the wrapped error for connection/context details
  2. If it is context cancellation, raise the timeout or avoid cancelling mid-transaction
  3. For network drivers, verify server connectivity and retry the transaction
  4. For embedded storage, check for file locks/corruption and repair
Defensive patterns

Strategy: try-catch

Try / catch

if err := tx.CloseIssue(ctx, id); err != nil {
	if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
		// retry with a longer-lived context
	}
	return err
}

Prevention

When it happens

Trigger: The underlying connection or driver encounters an I/O or protocol error while streaming rows from a dependency table, detected only after the loop finishes via rows.Err().

Common situations: Embedded DB file locked or disconnected mid-query; network interruption to a remote Dolt SQL server; context cancellation during long iteration.

Related errors


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