gastownhall/beads · critical
adding wisps.is_blocked: %w
Error message
adding wisps.is_blocked: %w
What it means
This wraps failure of `ALTER TABLE wisps ADD COLUMN is_blocked TINYINT(1) NOT NULL DEFAULT 0`, executed when the repair confirmed the column is missing. Unlike the check errors, this is a real DDL failure — the schema was about to be changed and the statement was rejected or aborted. On MySQL this commonly fails due to permissions, a duplicate-column race, table lock contention, or insufficient disk during a table rebuild.
Source
Thrown at internal/storage/schema/migration_repairs.go:281
}
if err := ensureWispIsBlockedColumn(ctx, db); err != nil {
return err
}
return ensureWispIsBlockedIndex(ctx, db)
}
// ensureWispIsBlockedColumn is ignored/0006's ADD COLUMN statement,
// translated to Go for a clone that reached this repair without it.
func ensureWispIsBlockedColumn(ctx context.Context, db DBConn) error {
hasColumn, err := schemaColumnExists(ctx, db, "wisps", "is_blocked")
if err != nil {
return fmt.Errorf("checking wisps.is_blocked column: %w", err)
}
if hasColumn {
return nil
}
if _, err := db.ExecContext(ctx, "ALTER TABLE wisps ADD COLUMN is_blocked TINYINT(1) NOT NULL DEFAULT 0"); err != nil {
return fmt.Errorf("adding wisps.is_blocked: %w", err)
}
return nil
}
// ensureWispIsBlockedIndex is ignored/0006's CREATE INDEX statement,
// translated to Go alongside ensureWispIsBlockedColumn above.
func ensureWispIsBlockedIndex(ctx context.Context, db DBConn) error {
hasIndex, err := schemaIndexExists(ctx, db, "wisps", "idx_wisps_is_blocked")
if err != nil {
return fmt.Errorf("checking idx_wisps_is_blocked index: %w", err)
}
if hasIndex {
return nil
}
if _, err := db.ExecContext(ctx, "CREATE INDEX idx_wisps_is_blocked ON wisps(is_blocked, status)"); err != nil {
return fmt.Errorf("creating idx_wisps_is_blocked: %w", err)
}
return nilView on GitHub (pinned to 71377f2769)
Solutions
- Read the wrapped driver error: ER_DUP_FIELDNAME means another process already added the column — re-run the repair and it will no-op
- Grant ALTER privilege to the migration user
- Ensure only one repair runs at a time (lock or serialize repair runs)
- For lock-wait timeouts, run the DDL during a quiet window or upgrade to a MySQL/Dolt version with online DDL
- Free disk space if the error indicates the table rebuild ran out of room
Example fix
// before: two workers racing the same repair
go runRepair(db); go runRepair(db)
// after: serialize repairs
mu.Lock(); defer mu.Unlock()
if err := runRepair(db); err != nil { return err } Defensive patterns
Strategy: try-catch
Validate before calling
// ensure no concurrent repair and sufficient privileges before ALTER
var privOK int
_ = db.QueryRowContext(ctx,
"SELECT COUNT(*) FROM information_schema.user_privileges WHERE grantee = CURRENT_USER() AND privilege_type IN ('ALTER','CREATE')").Scan(&privOK)
if privOK == 0 {
return errors.New("repair user lacks ALTER privilege; aborting before DDL")
} Try / catch
if err := ensureWispIsBlockedForRecompute(ctx, db); err != nil {
var drv *mysql.MySQLError
if errors.As(err, &drv) {
switch drv.Number {
case 1060: // ER_DUP_FIELDNAME — column added concurrently, safe to re-run
return ensureWispIsBlockedForRecompute(ctx, db)
case 1205: // lock wait timeout
return fmt.Errorf("DDL blocked; retry in a quiet window: %w", err)
}
}
return err
} Prevention
- Serialize repair runs with a file/DB lock so only one process does DDL
- Grant ALTER to the migration user, not just SELECT/INSERT
- Handle ER_DUP_FIELDNAME as 'already done' and re-run to confirm no-op
- Run large-table DDL in a maintenance window with lock_wait_timeout raised
When it happens
Trigger: ensureWispIsBlockedColumn ran on a clone whose wisps table exists without is_blocked, and the ExecContext ALTER TABLE fails: missing ALTER privilege, another process concurrently adding the same column, metadata/DDL lock timeout, or disk-full during the implicit table copy.
Common situations: Two instances of the tool repairing the same database simultaneously; running repairs as a read-mostly user; large wisps tables making the DDL slow and prone to lock-wait timeouts on MySQL 5.x without online DDL.
Related errors
- adding dependencies.id for migration 0053: %w
- creating idx_wisps_is_blocked: %w
- schema: read database name: %w
- schema migration: %w
- checking wisps.is_blocked column: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/797338b2abd8c04d.
Report an issue: GitHub.