gastownhall/beads · error
deduplicating wisp_dependencies before the 0058 repair: %w
Error message
deduplicating wisp_dependencies before the 0058 repair: %w
What it means
This error wraps a SQL failure raised while deduplicating wisp_dependencies rows during the 0058 forward-shape schema repair. Before unique keys (uk_*) can be added, rows that collide on the natural identity (issue_id + null-safe depends_on columns) must be deleted; if the DELETE fails the repair aborts so it never adds keys over duplicate data.
Source
Thrown at internal/storage/schema/wisp_dep_forward_repair.go:445
// wisp-target rows as distinct because their NULL issue targets never compare
// equal. MIN(id) is an arbitrary but deterministic survivor, which is the
// property that matters -- it makes a resumed run pick the same row.
func dedupeWispDepNaturalIdentity(ctx context.Context, db DBConn) error {
if _, err := db.ExecContext(ctx, `
DELETE wd FROM wisp_dependencies wd
JOIN (
SELECT MIN(id) AS keep_id, issue_id, depends_on_issue_id, depends_on_wisp_id, depends_on_external
FROM wisp_dependencies
GROUP BY issue_id, depends_on_issue_id, depends_on_wisp_id, depends_on_external
HAVING COUNT(*) > 1
) dup
ON wd.issue_id = dup.issue_id
AND wd.depends_on_issue_id <=> dup.depends_on_issue_id
AND wd.depends_on_wisp_id <=> dup.depends_on_wisp_id
AND wd.depends_on_external <=> dup.depends_on_external
WHERE wd.id <> dup.keep_id
`); err != nil {
return fmt.Errorf("deduplicating wisp_dependencies before the 0058 repair: %w", err)
}
return nil
}
// ensureWispDepFinalKeysAndConstraints completes the final shape. Each object
// is added only if absent, so this finishes a partially-rebuilt table rather
// than failing on a duplicate key name -- and re-running it on a converged
// database does nothing at all.
func ensureWispDepFinalKeysAndConstraints(ctx context.Context, db DBConn) error {
for _, k := range wispDepFinalKeys {
present, err := schemaIndexExists(ctx, db, wispDepTable, k.name)
if err != nil {
return err
}
if present {
continue
}
if _, err := db.ExecContext(ctx, "ALTER TABLE wisp_dependencies "+k.definition); err != nil {View on GitHub (pinned to 71377f2769)
Solutions
- Ensure ensureWispDepSurrogateKey ran first — verify the wisp_dependencies.id column and its PRIMARY KEY exist before dedupe
- Run the migration/repair as a database user with DELETE and ALTER privileges on wisp_dependencies
- Inspect the wrapped MySQL/Dolt error for the root cause (syntax, lock wait, unknown column) and fix that underlying issue
- Back up the database, then re-run the repair; it is idempotent and resumes partially-repaired tables
Example fix
// before (fails: id column missing on legacy table) dbd upgrade // dedupe fails with "Unknown column 'id'" // after // run the full repair path so ensureWispDepSurrogateKey adds id before dedupe, // or manually: ALTER TABLE wisp_dependencies ADD COLUMN id CHAR(36) NOT NULL DEFAULT (UUID()) PRIMARY KEY FIRST;
Defensive patterns
Strategy: validation
Validate before calling
hasID, err := schemaColumnExists(ctx, db, "wisp_dependencies", "id")
if err != nil || !hasID {
return errors.New("run surrogate-key step before dedupe")
} Try / catch
if err := repairWispDependenciesForwardShape(ctx, db); err != nil {
log.Printf("0058 repair dedupe failed, database unchanged: %v", err)
return err
} Prevention
- Always run migrations/repairs through the tool's own upgrade path, not ad-hoc SQL
- Back up the database before schema repairs
- Use a DB account with DELETE and ALTER privileges
- Let the idempotent repair resume partially-repaired tables instead of hand-patching
When it happens
Trigger: Running the wisp_dependencies forward repair (repairWispDependenciesForwardShape) on a legacy-shaped store where the DELETE wd FROM wisp_dependencies wd JOIN (...) dup statement fails — e.g. missing id column (dedupe requires the surrogate id added by ensureWispDepSurrogateKey first), SQL syntax/permission errors, or a corrupted/locked table.
Common situations: Upgrading a pre-0058 beads database whose wisp_dependencies table still has the legacy composite primary key and accumulated duplicate rows; interrupted prior migrations leaving the table half-repaired; database user lacking DELETE/ALTER privileges.
Related errors
- pre-repair for migration %s: %w
- checking %s for the pre-0058 repair: %w
- checking %s.id for the pre-0058 repair: %w
- deleting wisp_dependencies rows rejected by the final shape:
- normalizing multi-target wisp_dependencies rows for the 0058
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/631d6bbe791cae84.
Report an issue: GitHub.