gastownhall/beads · error

query dependents from %s: %w

Error message

query dependents from %s: %w

What it means

ExternalDependentsBySourceInTx queries each dependency plane ('dependencies', 'wisp_dependencies') in batches for rows depending on the given ids. This error wraps a query-execution failure and names the offending table. A missing optional table is deliberately skipped via optionalBlockedTable + isTableNotExistError, so reaching this error means a real failure, not an absent plane.

Source

Thrown at internal/storage/issueops/delete_role.go:207

	}
	bySource := make(map[string]map[string]bool)
	for i := 0; i < len(ids); i += deleteBatchSize {
		end := i + deleteBatchSize
		if end > len(ids) {
			end = len(ids)
		}
		inClause, args := buildSQLInClause(ids[i:end])

		for _, depTable := range []string{"dependencies", "wisp_dependencies"} {
			rows, err := tx.QueryContext(ctx,
				fmt.Sprintf(`SELECT %s AS depends_on_id, issue_id FROM %s WHERE %s`,
					DepTargetExpr, depTable, depTargetIn("", inClause)),
				args...)
			if err != nil {
				if optionalBlockedTable(depTable) && isTableNotExistError(err) {
					continue
				}
				return nil, fmt.Errorf("query dependents from %s: %w", depTable, err)
			}
			for rows.Next() {
				var target, dependent string
				if err := rows.Scan(&target, &dependent); err != nil {
					_ = rows.Close()
					return nil, fmt.Errorf("scan dependent: %w", err)
				}
				if idSet[dependent] {
					continue
				}
				if bySource[target] == nil {
					bySource[target] = make(map[string]bool)
				}
				bySource[target][dependent] = true
			}
			_ = rows.Close()
			if err := rows.Err(); err != nil {
				return nil, fmt.Errorf("iterate dependents from %s: %w", depTable, err)

View on GitHub (pinned to 71377f2769)

Solutions

  1. Read the wrapped driver error and the named table in the message
  2. If the table should be optional, check whether isTableNotExistError recognizes your driver's error (driver/version mismatch)
  3. Restore connectivity or the transaction and retry
  4. Update the storage driver/backend to a compatible version
  5. Retry the operation; the query is read-only and safe to re-run
Defensive patterns

Strategy: try-catch

Validate before calling

// confirm both planes exist before deleting on your backend
for _, t := range []string{"dependencies", "wisp_dependencies"} {
    if err := store.PingTable(ctx, t); err != nil { return fmt.Errorf("missing table %s", t) }
}

Type guard

if strings.Contains(err.Error(), "query dependents from ") {
    table := extractTable(err) // which plane failed
    _ = table
}

Try / catch

_, err := store.Delete(ctx, req)
if err != nil && strings.Contains(err.Error(), "query dependents from") {
    log.Printf("dependents query failed: %v", errors.Unwrap(err))
}

Prevention

When it happens

Trigger: tx.QueryContext on 'dependencies' or 'wisp_dependencies' returns an error that is not a tolerated 'table not exist' — connection failure, SQL/driver error, or cancelled context inside the batched IN query.

Common situations: DB connection dropped mid-delete; context cancellation; driver incompatibility producing unexpected SQL errors; a genuinely absent optional table whose error text is not recognized by isTableNotExistError on your driver version.

Related errors


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