{"record":{"id":"8fb32c3a17cf06f2","repo":"gastownhall/beads","slug":"rekey-dependency-ids-w","errorCode":null,"errorMessage":"rekey dependency ids: %w","messagePattern":"rekey dependency ids: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/schema/schema.go","lineNumber":672,"sourceCode":"\n\tapplied, mainColumnAdded, err := mainSource.migrate(ctx, db, 0)\n\tif err != nil {\n\t\treturn applied, err\n\t}\n\n\tbackfilled, err := ensureBackfilledCustomStatusesCustomTypes(ctx, db)\n\tif err != nil {\n\t\treturn applied, fmt.Errorf(\"backfill custom tables: %w\", err)\n\t}\n\n\t// #4259: rewrite any per-clone-random dependency ids (minted by 0043's\n\t// DEFAULT (UUID()) before this fix) to the deterministic key, so independently\n\t// migrated clones converge to byte-identical, merge-safe dependencies. Runs\n\t// here, after the schema migrations (0050 has asserted the canonical schema),\n\t// and only on a pass where migration work was needed.\n\trekeyed, err := rekeyDependencyIDs(ctx, db)\n\tif err != nil {\n\t\treturn applied, fmt.Errorf(\"rekey dependency ids: %w\", err)\n\t}\n\tbackfilled = backfilled || rekeyed\n\n\t// bd-6dnrw.2: converge the events/comments/snapshots primary keys that\n\t// migration 0037 randomized per-clone, the same hazard class on the aux\n\t// tables. Gated on the clone-local ignored marker (recorded later in this\n\t// pass by ignoredSource.migrate) so it runs exactly once per clone instead\n\t// of churning synced rows on every later migration pass — and on the\n\t// pre-pass main cursor, so fresh clones of converged lineages record the\n\t// marker without re-running the rewrite (bd-578h9.4).\n\t// ...and the bd-ri8bd sibling: one more pass over the same tables for the\n\t// rows minted with random UUIDv7 ids between the initial backfill and the\n\t// switch to content-derived ids at insert time. Same machinery, own\n\t// marker/sentinel/shipped-version gates, one shared cursor read.\n\tauxRekeyed, err := rekeyAuxRowIDsAllPasses(ctx, db, mainVersionBefore)\n\tif err != nil {\n\t\treturn applied, fmt.Errorf(\"rekey aux row ids: %w\", err)\n\t}","sourceCodeStart":654,"sourceCodeEnd":690,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/schema/schema.go#L654-L690","documentation":"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.","triggerScenarios":"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.","commonSituations":"Old clones migrated by beads versions predating the #4259 fix; dependencies duplicated such that the deterministic key collides; storage errors during large dependency rewrites.","solutions":["Inspect the wrapped cause for the failing rekey statement (often a duplicate-key collision)","Resolve conflicting/duplicate dependency rows so the deterministic key is unique, then re-run MigrateUp","Verify no concurrent writer is touching the dependencies table during the pass","If state is ambiguous after a crash mid-rekey, restore from the last Dolt commit and retry"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Detect duplicate dependency keys that would collide on deterministic rekey\nrows, err := db.QueryContext(ctx,\n    \"SELECT issue_id, COUNT(*) c FROM dependencies GROUP BY issue_id, depends_on_id HAVING c > 1\")\n// non-empty rows => resolve duplicates before migrating","typeGuard":"func isDependencyRekeyErr(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"rekey dependency ids\")\n}","tryCatchPattern":"applied, err := schema.MigrateUp(ctx, db)\nif isDependencyRekeyErr(err) {\n    // mid-pass failure: dedupe dependencies, then retry the pass\n    if derr := dedupeDependencies(ctx, db); derr != nil { return derr }\n    return schema.MigrateUp(ctx, db)\n}","preventionTips":["Upgrade through beads versions in order so the #4259 fix runs once cleanly","Deduplicate dependencies on old clones before upgrading","Do not kill the process during the migration pass"],"tags":["database","migration","rekey","dependencies","dolt"],"backgroundTag":"migration-rekey-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}