gastownhall/beads · error
wisp_dependencies: %w
Error message
wisp_dependencies: %w
What it means
Same family as the dependencies error but for wisp_dependencies: rekeyDependencyIDs wraps failures from re-keying the wisp_dependencies edge table. Note wisp_dependencies is dolt-ignored, so this re-key stays clone-local and does not participate in pull-based convergence — a failure here affects only the local clone.
Source
Thrown at internal/storage/schema/dep_id_backfill.go:36
// id. Leaving them would keep two independently-migrated clones divergent (same
// edge, different primary key) and break `bd dolt pull`. This rewrites them to
// the deterministic value so two clones converge to byte-identical dependencies.
//
// It runs from MigrateUp right after the schema migrations (so 0050 has already
// asserted the canonical schema), and only on a pass where migration work was
// needed — it is not part of the steady-state open path. It is idempotent: a row
// already keyed deterministically is skipped, so re-running on a later migration
// pass is a cheap no-op. dependencies changes are staged and committed by
// MigrateUp; wisp_dependencies is dolt-ignored, so its re-key stays clone-local
// (it only escapes on promotion, which copies the id).
func rekeyDependencyIDs(ctx context.Context, db DBConn) (bool, error) {
wroteDeps, err := rekeyDependencyTable(ctx, db, "dependencies")
if err != nil {
return wroteDeps, fmt.Errorf("dependencies: %w", err)
}
wroteWisp, err := rekeyDependencyTable(ctx, db, "wisp_dependencies")
if err != nil {
return wroteDeps || wroteWisp, fmt.Errorf("wisp_dependencies: %w", err)
}
return wroteDeps || wroteWisp, nil
}
// rekeyDependencyTable re-derives ids for one edge table. table must be a
// hardcoded constant ("dependencies" or "wisp_dependencies").
func rekeyDependencyTable(ctx context.Context, db DBConn, table string) (bool, error) {
// Skip cleanly if the table or its id column isn't present (e.g. an older or
// partial schema where the surrogate key was never added): nothing to re-key.
hasID, err := columnExists(ctx, db, table, "id")
if err != nil {
return false, err
}
if !hasID {
return false, nil
}
// The natural target is the single non-null of the three typed columns —View on GitHub (pinned to 71377f2769)
Solutions
- Inspect the wrapped inner error for the specific failing statement
- Check for duplicate wisp edges that would collide on the deterministic id and deduplicate them
- Re-run the migration pass — the re-key is idempotent
- If wisp_dependencies lacks the id column (older schema), the pass skips cleanly; verify with the INFORMATION_SCHEMA.COLUMNS query
Defensive patterns
Strategy: try-catch
Validate before calling
-- same preflight for wisp_dependencies (clone-local) SELECT issue_id, COALESCE(depends_on_issue_id, depends_on_wisp_id, depends_on_external) t, COUNT(*) c FROM wisp_dependencies GROUP BY issue_id, t HAVING c > 1;
Try / catch
if _, err := rekeyDependencyIDs(ctx, db); err != nil {
if dberrors.IsUniqueViolation(err) {
return fmt.Errorf("dedupe wisp edges: %w", err)
}
return err
} Prevention
- Remember wisp_dependencies rekeys are clone-local — fix per clone
- Apply migrations in order (0043 → 0050) before backfill runs
- Verify the id column exists on older schemas (the pass skips otherwise)
When it happens
Trigger: rekeyDependencyTable(ctx, db, "wisp_dependencies") fails — the same failure modes as the dependencies pass: schema probe error, SELECT failure, scan error, or an UPDATE re-key failing (e.g. unique-key collision on depid-derived ids).
Common situations: Old clones carrying UUID-keyed wisp rows from before migration 0050; connection drops mid-migration; duplicate wisp edges resolving to the same deterministic id; partial/older schema lacking the typed target columns.
Related errors
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/56a374dad471e2cc.
Report an issue: GitHub.