gastownhall/beads · error

rekey dependency ids

Error message

rekey dependency ids: %w

What it means

This error wraps a failure in rekeyDependencyIDs, which rewrites per-clone-random dependency primary keys (#4259) to the deterministic content-derived key so independently migrated clones converge to merge-safe data. It runs after main migrations succeeded, so the failure leaves the pass partially applied and the applied count is still returned.

Solutions

  1. Inspect the wrapped cause for the failing rekey statement (often a duplicate-key collision)
  2. Resolve conflicting/duplicate dependency rows so the deterministic key is unique, then re-run MigrateUp
  3. Verify no concurrent writer is touching the dependencies table during the pass
  4. If state is ambiguous after a crash mid-rekey, restore from the last Dolt commit and retry
Defensive patterns

Strategy: retry

Validate before calling

// Detect duplicate dependency keys that would collide on deterministic rekey
rows, err := db.QueryContext(ctx,
    "SELECT issue_id, COUNT(*) c FROM dependencies GROUP BY issue_id, depends_on_id HAVING c > 1")
// non-empty rows => resolve duplicates before migrating

Type guard

func isDependencyRekeyErr(err error) bool {
    return err != nil && strings.Contains(err.Error(), "rekey dependency ids")
}

Try / catch

applied, err := schema.MigrateUp(ctx, db)
if isDependencyRekeyErr(err) {
    // mid-pass failure: dedupe dependencies, then retry the pass
    if derr := dedupeDependencies(ctx, db); derr != nil { return derr }
    return schema.MigrateUp(ctx, db)
}

Prevention

When it happens

Trigger: Calling MigrateUp/MigrateUpWithLock on a database with legacy UUID()-keyed dependency rows where the rekey UPDATE fails - duplicate deterministic keys after rewrite, constraint violations, or Dolt write/commit errors mid-rekey.

Common situations: Old clones migrated by beads versions predating the #4259 fix; dependencies duplicated such that the deterministic key collides; storage errors during large dependency rewrites.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/8fb32c3a17cf06f2. Report an issue: GitHub.

Appendix: source

Thrown at internal/storage/schema/schema.go:672

	applied, mainColumnAdded, err := mainSource.migrate(ctx, db, 0)
	if err != nil {
		return applied, err
	}

	backfilled, err := ensureBackfilledCustomStatusesCustomTypes(ctx, db)
	if err != nil {
		return applied, fmt.Errorf("backfill custom tables: %w", err)
	}

	// #4259: rewrite any per-clone-random dependency ids (minted by 0043's
	// DEFAULT (UUID()) before this fix) to the deterministic key, so independently
	// migrated clones converge to byte-identical, merge-safe dependencies. Runs
	// here, after the schema migrations (0050 has asserted the canonical schema),
	// and only on a pass where migration work was needed.
	rekeyed, err := rekeyDependencyIDs(ctx, db)
	if err != nil {
		return applied, fmt.Errorf("rekey dependency ids: %w", err)
	}
	backfilled = backfilled || rekeyed

	// bd-6dnrw.2: converge the events/comments/snapshots primary keys that
	// migration 0037 randomized per-clone, the same hazard class on the aux
	// tables. Gated on the clone-local ignored marker (recorded later in this
	// pass by ignoredSource.migrate) so it runs exactly once per clone instead
	// of churning synced rows on every later migration pass — and on the
	// pre-pass main cursor, so fresh clones of converged lineages record the
	// marker without re-running the rewrite (bd-578h9.4).
	// ...and the bd-ri8bd sibling: one more pass over the same tables for the
	// rows minted with random UUIDv7 ids between the initial backfill and the
	// switch to content-derived ids at insert time. Same machinery, own
	// marker/sentinel/shipped-version gates, one shared cursor read.
	auxRekeyed, err := rekeyAuxRowIDsAllPasses(ctx, db, mainVersionBefore)
	if err != nil {
		return applied, fmt.Errorf("rekey aux row ids: %w", err)
	}

View on GitHub (pinned to 71377f2769)