gastownhall/beads · error
keying dependencies.id for migration 0053: %w
Error message
keying dependencies.id for migration 0053: %w
What it means
Wraps failure of `ALTER TABLE dependencies ADD PRIMARY KEY (id)` — the last step of migration 0053, restoring id as the table's primary key after the drifted key was dropped and all ids were backfilled.
Source
Thrown at internal/storage/schema/migration_repairs.go:553
return fmt.Errorf("finalizing dependencies.id for migration 0053: %w", err)
}
hasAnyPrimaryKey, err := schemaHasPrimaryKey(ctx, db, "dependencies")
if err != nil {
return fmt.Errorf("checking dependencies for an existing primary key: %w", err)
}
if hasAnyPrimaryKey {
// The #4690 drifted shape has dependencies keyed some other way (or
// keyless): a table can carry only one PRIMARY KEY, so whatever is
// there must go before id can become it. The uk_dep_* natural-identity
// unique keys (0043) enforce the real uniqueness independently of
// whatever this was, so dropping it is safe.
if _, err := db.ExecContext(ctx, "ALTER TABLE dependencies DROP PRIMARY KEY"); err != nil {
return fmt.Errorf("dropping dependencies' existing primary key for migration 0053: %w", err)
}
}
if _, err := db.ExecContext(ctx, "ALTER TABLE dependencies ADD PRIMARY KEY (id)"); err != nil {
return fmt.Errorf("keying dependencies.id for migration 0053: %w", err)
}
return nil
}
// firstNonNullString returns the first valid (non-NULL) value among cols, or
// "" if all are NULL.
func firstNonNullString(cols ...sql.NullString) string {
for _, c := range cols {
if c.Valid {
return c.String
}
}
return ""
}
// ensureIssuesRigColumns repairs #4502: the rig/agent columns were only ever
// added to the squashed bootstrap 0001_create_issues, so a database
// bootstrapped before they existed reaches schema v52 without them, andView on GitHub (pinned to 71377f2769)
Solutions
- Rerun `bd` with exclusive access (no other bd processes or SQL sessions)
- Check for duplicate natural identities: GROUP BY issue_id, depends_on_issue_id, depends_on_wisp_id, depends_on_external HAVING COUNT(*) > 1 and deduplicate
- Verify remainingNull == 0 and no duplicated CHAR(36) ids before retrying
- Grant ALTER/INDEX if the wrapped error is a privilege error
Example fix
// before: duplicate natural-identity rows collide on derived id bd dolt sql -q "SELECT issue_id, depends_on_issue_id, COUNT(*) c FROM dependencies GROUP BY 1,2 HAVING c > 1" // after: deduplicate, then rerun bd ready
Defensive patterns
Strategy: validation
Validate before calling
-- must return zero rows before the repair can key dependencies.id SELECT issue_id, depends_on_issue_id, depends_on_wisp_id, depends_on_external, COUNT(*) c FROM dependencies GROUP BY 1,2,3,4 HAVING c > 1; SELECT COUNT(*) FROM dependencies WHERE id IS NULL;
Try / catch
if err := ensureSchema(ctx, db); err != nil {
if strings.Contains(err.Error(), "keying dependencies.id for migration 0053") {
if strings.Contains(err.Error(), "Duplicate") { return fmt.Errorf("dedupe natural-identity rows, then retry") }
return retryWithBackoff(ensureSchema)
}
return err
} Prevention
- Deduplicate dependency rows before upgrading old databases
- Ensure only one bd process writes during migration
- Backfill interruptions: rerun rather than hand-inserting ids
- Keep uk_dep_* unique keys intact
When it happens
Trigger: ADD PRIMARY KEY fails: duplicate non-NULL id values exist (backfill produced a collision), a NULL id slipped through, the table is locked by another writer, privileges are missing, or the connection dropped during the ALTER.
Common situations: Concurrent bd sessions inserting dependencies during the repair; a previously interrupted run that keyed rows inconsistently; manual SQL inserted duplicate natural-identity rows so the derived ids collide.
Related errors
- failed to scan peer for migration: %w
- failed to iterate peers for migration: %w
- failed to update encrypted password for peer %s: %w
- re-key id %s -> %s: %w
- backfilling dependencies.id for migration 0053: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/78dbeb2f6f8c9835.
Report an issue: GitHub.