gastownhall/beads · error
adding wisp_dependencies.%s for migration 0053: %w
Error message
adding wisp_dependencies.%s for migration 0053: %w
What it means
Wraps a failed ALTER TABLE wisp_dependencies ADD COLUMN when ensureWispDependenciesSplitTargets adds a missing split-target column (depends_on_issue_id/depends_on_wisp_id/depends_on_external) required by migration 0053. This is an actual DDL failure, so the schema may be partially repaired (some columns added, then one fails). The function is safe to re-run: present columns are skipped.
Source
Thrown at internal/storage/schema/migration_repairs.go:632
// after that the source data needed to finish an interrupted backfill is
// gone for good.
func ensureWispDependenciesSplitTargets(ctx context.Context, db DBConn) error {
table, err := schemaTableExists(ctx, db, "wisp_dependencies")
if err != nil {
return fmt.Errorf("checking wisp_dependencies table: %w", err)
}
if !table {
return nil
}
for _, col := range wispDependenciesSplitTargetColumns() {
present, err := schemaColumnExists(ctx, db, "wisp_dependencies", col.name)
if err != nil {
return fmt.Errorf("checking wisp_dependencies.%s: %w", col.name, err)
}
if !present {
if _, err := db.ExecContext(ctx, "ALTER TABLE wisp_dependencies ADD COLUMN "+col.name+" "+col.definition); err != nil {
return fmt.Errorf("adding wisp_dependencies.%s for migration 0053: %w", col.name, err)
}
}
}
legacyTarget, err := schemaColumnExists(ctx, db, "wisp_dependencies", "depends_on_id")
if err != nil {
return fmt.Errorf("checking wisp_dependencies.depends_on_id: %w", err)
}
if !legacyTarget {
// Nothing left to backfill from: either a prior pass already
// finished (depends_on_id has since been dropped) or this database
// never had the legacy column to begin with.
return nil
}
for _, repair := range wispDependenciesSplitTargetBackfillSQL() {
if _, err := db.ExecContext(ctx, repair); err != nil {
return fmt.Errorf("backfilling wisp_dependencies split targets for migration 0053: %w", err)View on GitHub (pinned to 71377f2769)
Solutions
- Read the wrapped driver error: if 'duplicate column', a concurrent repair already added it — simply re-run and it will skip present columns.
- Ensure only one process performs migrations at a time (use a lock or run `bd migrate` in a single session).
- Confirm the database is writable (not opened read-only) and the user has ALTER privilege.
- Re-run the repair; each step is idempotent and safe to repeat.
Defensive patterns
Strategy: try-catch
Validate before calling
// check column and skip ALTER if another process already added it
present, _ := schemaColumnExists(ctx, db, "wisp_dependencies", colName)
if present { /* skip ALTER */ } Type guard
func isDuplicateColumnErr(err error) bool {
return strings.Contains(err.Error(), "Duplicate column name")
} Try / catch
err := ensureWispDependenciesSplitTargets(ctx, db)
if err != nil && isDuplicateColumnErr(err) {
// concurrent repair won the race; safe to proceed
} else if err != nil {
return err
} Prevention
- Serialize migrations with a lock (single migrator process)
- Open the database read-write, never read-only, for repairs
- Grant the DB user ALTER privilege
- Ensure sufficient disk space before DDL
When it happens
Trigger: db.ExecContext("ALTER TABLE wisp_dependencies ADD COLUMN <name> <definition>") fails — duplicate column name raced in by a concurrent process, table locked by another writer, Dolt refusing DDL in the current session, or disk/resource errors.
Common situations: Two `bd` processes running migration repair concurrently on the same database; database opened read-only; Dolt version that rejects ALTER on a table with pending foreign keys; out-of-disk during DDL.
Related errors
- adding wisps.is_blocked: %w
- adding dependencies.id for migration 0053: %w
- finalizing dependencies.id for migration 0053: %w
- dropping dependencies' existing primary key for migration 00
- adding issues.%s for migration 0053: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/b7d3479609bfa347.
Report an issue: GitHub.