gastownhall/beads · error

check remaining blocker status: %w

Error message

check remaining blocker status: %w

What it means

Wraps a failure from loadStatusByIDInTx while fetching statuses of remaining blocker issues inside GetNewlyUnblockedByCloseInTx. The dependency edges were read fine, but resolving whether each blocker is still open/closed/pinned failed, so the function cannot safely decide which candidates became unblocked.

Source

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

					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
				}
			}
		}
	}

	var unblocked []*types.Issue
	for _, id := range candidateIDs {
		if stillBlocked[id] {
			continue
		}
		issue, err := GetIssueInTx(ctx, tx, id)

View on GitHub (pinned to 71377f2769)

Solutions

  1. Inspect the wrapped error from loadStatusByIDInTx for the root cause
  2. Verify the issues table exists with the expected id/status columns
  3. Resolve lock contention (retry the transaction) if the error is a deadlock/timeout
  4. Run storage integrity checks/repairs if corruption is indicated
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure issues table is healthy
_ = db.QueryRow("SELECT COUNT(*) FROM issues WHERE status != ''").Scan(&n)

Try / catch

if err := tx.CloseIssue(ctx, id); err != nil {
	if strings.Contains(err.Error(), "check remaining blocker status") {
		// inspect issues-table health, then retry
	}
	return err
}

Prevention

When it happens

Trigger: The batch status lookup for remainingBlockerIDs fails — e.g. the issues table query inside loadStatusByIDInTx errors due to schema problems, lock contention, or driver errors.

Common situations: Issues table missing or migrated to an unexpected shape; transaction deadlock/lock timeout with concurrent writers; embedded DB corruption.

Understand the failure class

Background: "query failed", "%w: SQL error" — wrapped database query errors in Go libraries explained — this error's family across 3 libraries.

Related errors


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