gastownhall/beads · critical
backfilling wisp_dependencies split targets for migration 00
Error message
backfilling wisp_dependencies split targets for migration 0053: %w
What it means
Wraps a failed backfill UPDATE while copying legacy depends_on_id values into the split-target columns (depends_on_external / depends_on_wisp_id / depends_on_issue_id) as part of migration 0053 repair. This is critical to fix before migration 0005 runs: 0005 drops depends_on_id, after which the source data for an interrupted backfill is gone forever. The statements are idempotent (each updates only rows not yet filled), so a retry is safe.
Source
Thrown at internal/storage/schema/migration_repairs.go:650
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)
}
}
return nil
}
func wispDependenciesSplitTargetColumns() []struct{ name, definition string } {
return []struct{ name, definition string }{
{"depends_on_issue_id", "VARCHAR(255) NULL"},
{"depends_on_wisp_id", "VARCHAR(255) NULL"},
{"depends_on_external", "VARCHAR(255) NULL"},
}
}
func wispDependenciesSplitTargetBackfillSQL() []string {
return []string{
"UPDATE wisp_dependencies SET depends_on_external = depends_on_id WHERE depends_on_external IS NULL AND depends_on_id LIKE 'external:%'",
"UPDATE wisp_dependencies wd JOIN wisps w ON w.id = wd.depends_on_id SET wd.depends_on_wisp_id = wd.depends_on_id WHERE wd.depends_on_wisp_id IS NULL AND wd.depends_on_external IS NULL",
"UPDATE wisp_dependencies wd JOIN issues i ON i.id = wd.depends_on_id SET wd.depends_on_issue_id = wd.depends_on_id WHERE wd.depends_on_issue_id IS NULL AND wd.depends_on_external IS NULL AND wd.depends_on_wisp_id IS NULL",View on GitHub (pinned to 71377f2769)
Solutions
- Read the wrapped driver error; if it is a lock/timeout issue, retry when the conflicting writer is done — the backfill is scoped and idempotent.
- DO NOT run or ignore migration 0005 until this backfill succeeds; depends_on_id is dropped by 0005 and the data would be unrecoverable.
- Verify referenced rows exist: for depends_on_id values, check matching rows in wisps and issues tables.
- Restore from Dolt history/backup if rows were corrupted, then re-run the repair before proceeding past 0005.
Defensive patterns
Strategy: validation
Validate before calling
// before letting migration 0005 run, verify the backfill completed var unfilled int db.QueryRowContext(ctx, `SELECT COUNT(*) FROM wisp_dependencies WHERE depends_on_id IS NOT NULL AND depends_on_external IS NULL AND depends_on_wisp_id IS NULL AND depends_on_issue_id IS NULL`).Scan(&unfilled) // unfilled > 0 with depends_on_id still present means backfill incomplete
Type guard
func backfillComplete(rowsFilled, rowsTotal int) bool { return rowsFilled == rowsTotal } Try / catch
if err := ensureWispDependenciesSplitTargets(ctx, db); err != nil {
// DO NOT proceed to migration 0005; depends_on_id would be dropped
return fmt.Errorf("refusing to continue toward migration 0005: %w", err)
} Prevention
- Never skip past a failed backfill — migration 0005 drops depends_on_id and the data becomes unrecoverable
- Back up the database (Dolt history/branch) before running repairs
- Run backfill when no concurrent writers hold locks on wisp_dependencies
- Verify referenced ids exist in wisps/issues before joining
When it happens
Trigger: One of the four UPDATE statements in wispDependenciesSplitTargetBackfillSQL() fails — a JOIN to wisps/issues hits a corrupt/missing row, a constraint violation on the target column, lock contention, or server failure mid-statement.
Common situations: Interrupted first attempt left columns present but unpopulated and a retry now fails on data issues; wisps/issues tables missing rows referenced by depends_on_id; concurrent writers holding row locks on wisp_dependencies.
Related errors
- %s: %w
- backfill custom_types: %w
- backfill custom_statuses: %w
- backfilling dependencies.id for migration 0053: %w
- backfill custom tables: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/108e15a76b8af000.
Report an issue: GitHub.