{"record":{"id":"78dbeb2f6f8c9835","repo":"gastownhall/beads","slug":"keying-dependencies-id-for-migration-0053-w","errorCode":null,"errorMessage":"keying dependencies.id for migration 0053: %w","messagePattern":"keying dependencies\\.id for migration 0053: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/schema/migration_repairs.go","lineNumber":553,"sourceCode":"\t\treturn fmt.Errorf(\"finalizing dependencies.id for migration 0053: %w\", err)\n\t}\n\n\thasAnyPrimaryKey, err := schemaHasPrimaryKey(ctx, db, \"dependencies\")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"checking dependencies for an existing primary key: %w\", err)\n\t}\n\tif hasAnyPrimaryKey {\n\t\t// The #4690 drifted shape has dependencies keyed some other way (or\n\t\t// keyless): a table can carry only one PRIMARY KEY, so whatever is\n\t\t// there must go before id can become it. The uk_dep_* natural-identity\n\t\t// unique keys (0043) enforce the real uniqueness independently of\n\t\t// whatever this was, so dropping it is safe.\n\t\tif _, err := db.ExecContext(ctx, \"ALTER TABLE dependencies DROP PRIMARY KEY\"); err != nil {\n\t\t\treturn fmt.Errorf(\"dropping dependencies' existing primary key for migration 0053: %w\", err)\n\t\t}\n\t}\n\tif _, err := db.ExecContext(ctx, \"ALTER TABLE dependencies ADD PRIMARY KEY (id)\"); err != nil {\n\t\treturn fmt.Errorf(\"keying dependencies.id for migration 0053: %w\", err)\n\t}\n\treturn nil\n}\n\n// firstNonNullString returns the first valid (non-NULL) value among cols, or\n// \"\" if all are NULL.\nfunc firstNonNullString(cols ...sql.NullString) string {\n\tfor _, c := range cols {\n\t\tif c.Valid {\n\t\t\treturn c.String\n\t\t}\n\t}\n\treturn \"\"\n}\n\n// ensureIssuesRigColumns repairs #4502: the rig/agent columns were only ever\n// added to the squashed bootstrap 0001_create_issues, so a database\n// bootstrapped before they existed reaches schema v52 without them, and","sourceCodeStart":535,"sourceCodeEnd":571,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/schema/migration_repairs.go#L535-L571","documentation":"Wraps failure of `ALTER TABLE dependencies ADD PRIMARY KEY (id)` — the last step of migration 0053, restoring id as the table's primary key after the drifted key was dropped and all ids were backfilled.","triggerScenarios":"ADD PRIMARY KEY fails: duplicate non-NULL id values exist (backfill produced a collision), a NULL id slipped through, the table is locked by another writer, privileges are missing, or the connection dropped during the ALTER.","commonSituations":"Concurrent bd sessions inserting dependencies during the repair; a previously interrupted run that keyed rows inconsistently; manual SQL inserted duplicate natural-identity rows so the derived ids collide.","solutions":["Rerun `bd` with exclusive access (no other bd processes or SQL sessions)","Check for duplicate natural identities: GROUP BY issue_id, depends_on_issue_id, depends_on_wisp_id, depends_on_external HAVING COUNT(*) > 1 and deduplicate","Verify remainingNull == 0 and no duplicated CHAR(36) ids before retrying","Grant ALTER/INDEX if the wrapped error is a privilege error"],"exampleFix":"// before: duplicate natural-identity rows collide on derived id\nbd dolt sql -q \"SELECT issue_id, depends_on_issue_id, COUNT(*) c FROM dependencies GROUP BY 1,2 HAVING c > 1\"\n// after: deduplicate, then rerun\nbd ready","handlingStrategy":"validation","validationCode":"-- must return zero rows before the repair can key dependencies.id\nSELECT issue_id, depends_on_issue_id, depends_on_wisp_id, depends_on_external, COUNT(*) c\nFROM dependencies\nGROUP BY 1,2,3,4\nHAVING c > 1;\nSELECT COUNT(*) FROM dependencies WHERE id IS NULL;","typeGuard":null,"tryCatchPattern":"if err := ensureSchema(ctx, db); err != nil {\n    if strings.Contains(err.Error(), \"keying dependencies.id for migration 0053\") {\n        if strings.Contains(err.Error(), \"Duplicate\") { return fmt.Errorf(\"dedupe natural-identity rows, then retry\") }\n        return retryWithBackoff(ensureSchema)\n    }\n    return err\n}","preventionTips":["Deduplicate dependency rows before upgrading old databases","Ensure only one bd process writes during migration","Backfill interruptions: rerun rather than hand-inserting ids","Keep uk_dep_* unique keys intact"],"tags":["database","migration","primary-key","sql"],"backgroundTag":"migration-backfill-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}