gastownhall/beads · error

rekey dependency ids: %w

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.

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)

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.