{"record":{"id":"8c2e5ce934a53785","repo":"gastownhall/beads","slug":"rekey-aux-row-ids-w","errorCode":null,"errorMessage":"rekey aux row ids: %w","messagePattern":"rekey aux row ids: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/schema/schema.go","lineNumber":689,"sourceCode":"\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}\n\tbackfilled = backfilled || auxRekeyed\n\n\ttouchedIgnoredDirtyTables, err := ignoredSource.pendingMigrationDirtyTables(ctx, db, dirtyBeforeAll)\n\tif err != nil {\n\t\treturn applied, fmt.Errorf(\"checking dirty tables against pending ignored migrations: %w\", err)\n\t}\n\tif len(touchedIgnoredDirtyTables) > 0 {\n\t\t// Deliberately a plain, untyped error (unlike the main-source guard\n\t\t// above, which returns *DirtyTablesError): this check fires mid-pass,\n\t\t// after the main-source migrations have already applied. A lenient\n\t\t// caller (embeddeddolt's openReadOnlyCommand / openWorkingSetReconcile\n\t\t// intents) skipping this and returning as if the open succeeded would\n\t\t// let a reconcile commit checkpoint a half-applied migration pass.\n\t\t// The ignored source also tracks bd-internal state (dolt_ignore'd\n\t\t// tables like ignored_schema_migrations), not expected user data, so\n\t\t// there is no dirty-commit recovery story to support here the way\n\t\t// there is for the main-source guard (#4566 scope).","sourceCodeStart":671,"sourceCodeEnd":707,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/schema/schema.go#L671-L707","documentation":"This error wraps a failure in rekeyAuxRowIDsAllPasses, the multi-pass rewrite that converges randomized primary keys on events/comments/snapshots tables (bd-6dnrw.2 and bd-ri8bd). Like the dependency rekey, it fires mid-pass after main migrations applied, so the returned applied count reflects work already done and the database may be mid-rewrite.","triggerScenarios":"Calling MigrateUp/MigrateUpWithLock where the aux rekey passes fail - duplicate content-derived keys on events/comments/snapshots, resume-sentinel state corruption from a previous crash (bd-578h9.16), or Dolt write errors during the batched UPDATEs.","commonSituations":"Crashed earlier passes leaving partial aux rekey updates; clones with rows minted between the backfill and the content-id switch; very large event tables hitting timeouts/storage limits mid-pass.","solutions":["Inspect the wrapped cause; a resume-pending sentinel means re-running MigrateUp should continue the interrupted rekey","Resolve duplicate ids or constraint violations surfaced by the wrapped error, then re-run","Avoid killing the process mid-pass; run migrations with the advisory lock (MigrateUpWithLock)","If the working set is stuck dirty from a partial pass, restore from the last Dolt commit and retry"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Check for a pending resume sentinel indicating an interrupted rekey\n// (resuming is expected and safe; just ensure storage is writable first)\nif _, err := db.ExecContext(ctx, \"SELECT 1\"); err != nil {\n    return fmt.Errorf(\"storage not writable for rekey resume: %w\", err)\n}","typeGuard":"func isAuxRekeyErr(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"rekey aux row ids\")\n}","tryCatchPattern":"applied, err := schema.MigrateUp(ctx, db)\nif isAuxRekeyErr(err) {\n    // rekey passes are resumable: retry after fixing the wrapped cause\n    return schema.MigrateUp(ctx, db)\n}","preventionTips":["Use MigrateUpWithLock so crashes mid-rekey are the only resume source","Avoid interrupting bd during upgrades (no SIGKILL mid-pass)","Keep adequate disk space for large event/comment table rewrites"],"tags":["database","migration","rekey","dolt","aux-tables"],"backgroundTag":"migration-rekey-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}