gastownhall/beads · error

checking index %s on %s: %w

Error message

checking index %s on %s: %w

What it means

Wraps a failure from schemaIndexExists, which probes INFORMATION_SCHEMA.STATISTICS to see whether a named index exists on a table (used by ensureWispIsBlockedIndex, dropWispDepLegacyShape, ensureWispDepFinalKeysAndConstraints). STATISTICS is used because plain secondary indexes are not constraints. Thrown only when the probe query itself fails, not when the index is missing.

Source

Thrown at internal/storage/schema/migration_repairs.go:717

	if err := db.QueryRowContext(ctx, `
		SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
		WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ? AND CONSTRAINT_TYPE = 'PRIMARY KEY'
	`, table).Scan(&count); err != nil {
		return false, err
	}
	return count > 0, nil
}

// schemaIndexExists reports whether table carries an index (or unique key) of
// the given name. STATISTICS rather than TABLE_CONSTRAINTS because plain
// secondary indexes are not constraints and never appear in the latter.
func schemaIndexExists(ctx context.Context, db DBConn, table, index string) (bool, error) {
	var count int
	if err := db.QueryRowContext(ctx, `
		SELECT COUNT(*) FROM INFORMATION_SCHEMA.STATISTICS
		WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ? AND INDEX_NAME = ?
	`, table, index).Scan(&count); err != nil {
		return false, fmt.Errorf("checking index %s on %s: %w", index, table, err)
	}
	return count > 0, nil
}

// schemaConstraintExists reports whether table carries a named constraint --
// foreign key or check. Unlike schemaHasPrimaryKey it asks about one specific
// name, which is what an add-if-absent step needs.
func schemaConstraintExists(ctx context.Context, db DBConn, table, constraint string) (bool, error) {
	var count int
	if err := db.QueryRowContext(ctx, `
		SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
		WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ? AND CONSTRAINT_NAME = ?
	`, table, constraint).Scan(&count); err != nil {
		return false, fmt.Errorf("checking constraint %s on %s: %w", constraint, table, err)
	}
	return count > 0, nil
}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Inspect the wrapped driver error and restore DB connectivity.
  2. Re-run the repair — index checks and their follow-up actions are idempotent add-if-absent operations.
  3. Confirm the DB user can query INFORMATION_SCHEMA.STATISTICS.
  4. Increase the context timeout if repairs are timing out on large databases.
Defensive patterns

Strategy: retry

Validate before calling

var n int
err := db.QueryRowContext(ctx, `SELECT COUNT(*) FROM INFORMATION_SCHEMA.STATISTICS
  WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=? AND INDEX_NAME=?`, table, index).Scan(&n)

Type guard

func isTransientDBErr(err error) bool {
    var ne net.Error
    return errors.As(err, &ne) || errors.Is(err, context.DeadlineExceeded)
}

Try / catch

if err := ensureWispIsBlockedIndex(ctx, db); err != nil {
    if isTransientDBErr(err) { return ensureWispIsBlockedIndex(ctx, db) } // idempotent
    return err
}

Prevention

When it happens

Trigger: The SELECT COUNT(*) FROM INFORMATION_SCHEMA.STATISTICS query errors during a repair step — Dolt server down, context cancelled, driver failure, or restricted permissions on INFORMATION_SCHEMA.

Common situations: Connection drop mid-repair; read-only account; Dolt server restart between repair steps; long migration exceeding ctx timeout.

Related errors


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