gastownhall/beads · error

query dependents for batch from %s: %w

Error message

query dependents for batch from %s: %w

What it means

FindAllDependentsInTx queries the dependencies/wisp_dependencies tables in batches to find dependents. A query error on a required table (one that is not an optional/absent table) is wrapped with this message naming the table. Table-not-exist errors are tolerated only for optional tables.

Source

Thrown at internal/storage/issueops/delete.go:435

			return nil, fmt.Errorf("cascade traversal discovered over %d issues; aborting to prevent runaway deletion", maxRecursiveResults)
		}
		batchEnd := deleteBatchSize
		if batchEnd > len(toProcess) {
			batchEnd = len(toProcess)
		}
		batch := toProcess[:batchEnd]
		toProcess = toProcess[batchEnd:]

		inClause, args := buildSQLInClause(batch)
		for _, depTable := range []string{"dependencies", "wisp_dependencies"} {
			rows, err := tx.QueryContext(ctx,
				fmt.Sprintf(`SELECT issue_id FROM %s WHERE %s`, depTable, depTargetIn("", inClause)),
				args...)
			if err != nil {
				if optionalBlockedTable(depTable) && isTableNotExistError(err) {
					continue
				}
				return nil, fmt.Errorf("query dependents for batch from %s: %w", depTable, err)
			}

			for rows.Next() {
				var depID string
				if err := rows.Scan(&depID); err != nil {
					_ = rows.Close()
					return nil, fmt.Errorf("scan dependent: %w", err)
				}
				if !result[depID] {
					result[depID] = true
					toProcess = append(toProcess, depID)
				}
			}
			_ = rows.Close()
			if err := rows.Err(); err != nil {
				return nil, fmt.Errorf("iterate dependents for batch from %s: %w", depTable, err)
			}
		}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Read the wrapped driver error; if the table is missing, run schema migration (bd doctor/migrate)
  2. Retry after resolving lock contention or restoring the connection
  3. Verify wisp_dependencies presence if you use wisp mode and it is treated as required

Example fix

// before
rows, err := tx.QueryContext(ctx, fmt.Sprintf(`SELECT issue_id FROM %s WHERE %s`, depTable, depTargetIn("", inClause)), args...)
// after — ensure schema is current first
// bd doctor; bd migrate (or equivalent) before retrying cascade delete
Defensive patterns

Strategy: try-catch

Validate before calling

// verify required dependency tables exist before cascade delete
for _, t := range []string{"dependencies"} {
	var n int
	db.QueryRow("SELECT COUNT(*) FROM sqlite_master WHERE name=?", t).Scan(&n)
	if n == 0 { return fmt.Errorf("missing table %s; migrate first", t) }
}

Try / catch

_, err := DeleteIssuesInTx(ctx, tx, ids, WithCascade())
if err != nil && strings.Contains(err.Error(), "query dependents for batch from") {
	if strings.Contains(err.Error(), "no such table") { migrate(db); return retry(ctx, ids) }
	return err
}

Prevention

When it happens

Trigger: ResolveDeletionSetInTx cascade traversal where SELECT issue_id FROM dependencies (or wisp_dependencies) fails — table does not exist and is not marked optional, SQL error, lock contention, or connection failure.

Common situations: Partially migrated or corrupted database missing a dependencies table; remote Dolt server connection reset mid-traversal; database locked by a concurrent writer.

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