{"record":{"id":"8bd6c04ddf07ccc1","repo":"gastownhall/beads","slug":"dropping-wisp-dependencies-depends-on-id-for-the-0","errorCode":null,"errorMessage":"dropping wisp_dependencies.depends_on_id for the 0058 repair: %w","messagePattern":"dropping wisp_dependencies\\.depends_on_id for the 0058 repair: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/schema/wisp_dep_forward_repair.go","lineNumber":365,"sourceCode":"\t}\n\n\thasPK, err := schemaHasPrimaryKey(ctx, db, wispDepTable)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif hasPK {\n\t\tif _, err := db.ExecContext(ctx, \"ALTER TABLE wisp_dependencies DROP PRIMARY KEY\"); err != nil {\n\t\t\treturn fmt.Errorf(\"dropping the wisp_dependencies primary key for the 0058 repair: %w\", err)\n\t\t}\n\t}\n\n\thasGenerated, err := schemaColumnExists(ctx, db, wispDepTable, \"depends_on_id\")\n\tif err != nil {\n\t\treturn err\n\t}\n\tif hasGenerated {\n\t\tif _, err := db.ExecContext(ctx, \"ALTER TABLE wisp_dependencies DROP COLUMN depends_on_id\"); err != nil {\n\t\t\treturn fmt.Errorf(\"dropping wisp_dependencies.depends_on_id for the 0058 repair: %w\", err)\n\t\t}\n\t}\n\treturn nil\n}\n\n// ensureWispDepSurrogateKey adds the final shape's id column and primary key.\n//\n// It is added BEFORE deduplication on purpose. The natural identity of a row\n// here is (issue_id, target), and two rows identical in every column have no\n// deterministic survivor -- created_at has second resolution and created_by and\n// type commonly take defaults, so ordinary retry inserts reach that state. Once\n// every row carries a distinct UUID a delete can pick MIN(id) deterministically.\n// The final primary key being the UUID also means ADD PRIMARY KEY can never\n// fail on duplicates, which is the state that made the previous designs fatal.\n//\n// A legacy store categorically has no id column: the original 0021 created the\n// composite-keyed shape without one, and ignored/0005 -- the only migration that\n// adds id to a legacy store -- drops the generated column in the same guarded","sourceCodeStart":347,"sourceCodeEnd":383,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/schema/wisp_dep_forward_repair.go#L347-L383","documentation":"Wraps a failure when dropping the generated column wisp_dependencies.depends_on_id (`ALTER TABLE wisp_dependencies DROP COLUMN depends_on_id`) during legacy-shape teardown. schemaColumnExists confirmed the column exists, but the DROP failed, aborting the repair before the surrogate key step.","triggerScenarios":"dropWispDepLegacyShape finds depends_on_id present and the ALTER TABLE DROP COLUMN errors — column still used by an index/constraint not yet dropped, privilege denial, lock timeout, or Dolt refusing to drop a column backing existing data.","commonSituations":"Crashed prior repair left indexes/constraints referencing depends_on_id; user lacks ALTER; concurrent DML blocking the table; Dolt version with restricted generated-column handling.","solutions":["Check the wrapped cause (%w) and remove any leftover index/constraint still referencing depends_on_id.","Re-run the full guarded repair so earlier drop steps complete in order.","Grant ALTER/DROP to the migration user and retry with no concurrent writers.","If Dolt blocks the drop, upgrade Dolt to a version supporting the column removal and re-run `bd`."],"exampleFix":"// before: DROP COLUMN fails — leftover index from a crashed pass\n// after: drop the leftover index, then resume\n// ALTER TABLE wisp_dependencies DROP INDEX <leftover>;\nif err := repairWispDependenciesForwardShape(ctx, db); err != nil {\n    return err\n}","handlingStrategy":"try-catch","validationCode":"// check for leftover indexes/constraints referencing depends_on_id before repair\nrows, err := db.QueryContext(ctx, `SELECT INDEX_NAME FROM information_schema.STATISTICS WHERE TABLE_NAME = 'wisp_dependencies' AND COLUMN_NAME = 'depends_on_id'`)\nif err != nil { log.Fatalf(\"cannot inspect depends_on_id usage: %v\", err) }\nrows.Close()","typeGuard":null,"tryCatchPattern":"if err := repairWispDependenciesForwardShape(ctx, db); err != nil {\n    if strings.Contains(err.Error(), \"dropping wisp_dependencies.depends_on_id\") {\n        // drop leftover indexes/constraints on depends_on_id, then re-run the guarded repair\n        return fmt.Errorf(\"clear depends_on_id dependents and re-run: %w\", err)\n    }\n    return err\n}","preventionTips":["Confirm Dolt version supports dropping generated columns before upgrading.","Let the repair's ordered drops (indexes → FKs → PK → column) run uninterrupted.","Grant ALTER/DROP to the migration user.","Avoid killing the process between drop steps; re-run the repair to resume."],"tags":["database","schema-repair","migration","generated-column","ddl"],"backgroundTag":"schema-migration-ddl-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}