gastownhall/beads · error

get dependency counts

Error message

get dependency counts (blockers from %s): %w

What it means

This error wraps the failure of the per-table 'blocks' count query in GetDependencyCountsInTx — a GROUP BY issue_id COUNT over a dependency table filtered to type='blocks'. It is returned only when the table is expected to exist (optional wisp table absence is skipped via isTableNotExistError), so it signals a real query failure on a present table.

Solutions

  1. Inspect the wrapped driver error to classify the root cause (missing column vs connection vs lock).
  2. Run migrations so the table has issue_id and type columns with supporting indexes for the GROUP BY.
  3. Retry on transient errors; investigate lock holders if 'lock wait timeout' appears.
  4. Verify the driver supports the exact SQL dialect used by the counts query.
  5. If it happens only for wisp_dependencies, the missing-table skip failed — check isTableNotExistError coverage for your driver.

Example fix

// before: wisp table missing but error not recognized, so counts abort
// after: ensure migrations create the table so classification never matters
CREATE TABLE IF NOT EXISTS wisp_dependencies (id VARCHAR(64) PRIMARY KEY, issue_id VARCHAR(64) NOT NULL, ...);
Defensive patterns

Strategy: validation

Validate before calling

// Confirm the blockers query preconditions: columns exist and table is present
rows, err := tx.QueryContext(ctx, "SELECT issue_id, type FROM dependencies WHERE type = 'blocks' LIMIT 1")
if err != nil { /* migration incomplete; hydration counts will fail */ }

Type guard

func blockersQueryReady(ctx context.Context, tx DBTX, table string) bool {
    var id string
    err := tx.QueryRowContext(ctx, "SELECT issue_id FROM "+table+" WHERE type = 'blocks' LIMIT 1").Scan(&id)
    return err == nil || isTableNotExistError(err)
}

Try / catch

counts, err := GetDependencyCountsInTx(ctx, tx, issueIDs)
if err != nil && strings.Contains(err.Error(), "blockers from ") {
    if isTableNotExistError(err) { /* wisp table edge case: verify optional-table skip */ }
    else { /* schema or connectivity problem: migrate/retry accordingly */ }
}

Prevention

When it happens

Trigger: Calling GetDependencyCountsInTx/HydrateReadyRowInTx when 'dependencies' (or a present 'wisp_dependencies') rejects the blockers query: schema drift (missing issue_id/type columns), SQL dialect incompatibility, context cancellation, connection failure, or lock contention.

Common situations: Schema drift after an aborted migration; remote database network issues during ready-row hydration; another process holding a long lock; driver version mismatch with the SQL used in the counts query.

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/c9667294feab942f. Report an issue: GitHub.

Appendix: source

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

		for i, id := range batch {
			placeholders[i] = "?"
			args[i] = id
		}
		inClause := strings.Join(placeholders, ",")

		for _, depTable := range depTables {
			//nolint:gosec // G201: depTable is hardcoded and inClause contains only ? placeholders.
			depRows, err := tx.QueryContext(ctx, fmt.Sprintf(`
				SELECT issue_id, COUNT(*) as cnt
				FROM %s
				WHERE issue_id IN (%s) AND type = 'blocks'
				GROUP BY issue_id
			`, depTable, inClause), args...)
			if err != nil {
				if optionalBlockedTable(depTable) && isTableNotExistError(err) {
					continue
				}
				return nil, fmt.Errorf("get dependency counts (blockers from %s): %w", depTable, err)
			}
			for depRows.Next() {
				var id string
				var cnt int
				if err := depRows.Scan(&id, &cnt); err != nil {
					_ = depRows.Close()
					return nil, fmt.Errorf("get dependency counts: scan blocker: %w", err)
				}
				if c, ok := result[id]; ok {
					c.DependencyCount += cnt
				}
			}
			_ = depRows.Close()
			if err := depRows.Err(); err != nil {
				return nil, fmt.Errorf("get dependency counts: blocker rows: %w", err)
			}

			//nolint:gosec // G201: depTable is hardcoded and inClause contains only ? placeholders.

View on GitHub (pinned to 71377f2769)