{"record":{"id":"968731596a610c51","repo":"gastownhall/beads","slug":"conflicts-resolved-with-s-strategy-but-merge-le","errorCode":null,"errorMessage":"conflicts resolved with '%s' strategy but merge left constraint violations bd cannot auto-repair; inspect dolt_constraint_violations and resolve before retrying","messagePattern":"conflicts resolved with '(.+?)' strategy but merge left constraint violations bd cannot auto-repair; inspect dolt_constraint_violations and resolve before retrying","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/versioncontrolops/mergesettle.go","lineNumber":328,"sourceCode":"\t\t\tabortMerge(ctx, db, preMergeClean)\n\t\t\treturn conflicts, fmt.Errorf(\"resolve %s conflicts: %w\", table, err)\n\t\t}\n\t\tdirtyTables[table] = true\n\t}\n\n\t// bd-6dnrw.4 / #4992: a strategy resolution can leave FK cascade\n\t// violations behind exactly like the auto-resolve path (e.g. --ours keeps\n\t// a child row whose parent was deleted on the other side); repair them the\n\t// same way so a strategy-resolved merge cannot silently commit a violated\n\t// working set.\n\trepaired, had, violErr := TryRepairFKCascadeViolations(ctx, db)\n\tif violErr != nil {\n\t\tabortMerge(ctx, db, preMergeClean)\n\t\treturn conflicts, violErr\n\t}\n\tif had && !repaired {\n\t\tabortMerge(ctx, db, preMergeClean)\n\t\treturn conflicts, fmt.Errorf(\"conflicts resolved with '%s' strategy but merge left constraint violations bd cannot auto-repair; inspect dolt_constraint_violations and resolve before retrying\", strategy)\n\t}\n\n\tif err := StageAndCommit(ctx, db, dirtyTables,\n\t\tfmt.Sprintf(\"Resolve merge conflicts from %s using %s strategy\", ref, strategy), author); err != nil {\n\t\tabortMerge(ctx, db, preMergeClean)\n\t\treturn conflicts, fmt.Errorf(\"conflicts resolved but commit failed: %w\", err)\n\t}\n\n\treturn conflicts, nil\n}\n\n// abortMerge restores the pre-merge state after a settle pass refused the\n// merge — the autocommit-mode stand-in for server mode's tx.Rollback().\n// DOLT_MERGE('--abort') is the precise tool but only works while merge state\n// is active; a force-committed violation-only merge may have closed it, so\n// fall back to a hard reset — but only when the working set was clean before\n// the merge ran. The most common reason --abort fails is a merge that\n// REFUSED TO START on a dirty working set; hard-resetting there would","sourceCodeStart":310,"sourceCodeEnd":346,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/versioncontrolops/mergesettle.go#L310-L346","documentation":"The chosen strategy (ours/theirs) resolved the conflicts, but Dolt still reports rows in dolt_constraint_violations that bd's automatic FK-cascade repair could not fix. Rather than commit a violating working set, the library aborts the merge and asks the user to inspect and resolve violations manually.","triggerScenarios":"After strategy resolution, a constraint-violation check finds violations (had=true) but the auto-repair pass repairs none or not all (repaired=false) — typically FK cascade violations left by --ours/--theirs resolution (bd-6dnrw.4 / #4992).","commonSituations":"Merging branches where one side deleted a parent row (issue) the other side still references (dependent row), and the strategy kept both sides inconsistently.","solutions":["Query `SELECT * FROM dolt_constraint_violations` (and its per-table variants) to see the violating rows","Delete or fix the violating rows (e.g. remove orphaned dependents or restore the missing parent), then re-run the merge","Prefer a strategy or pre-merge cleanup that removes dependents of deleted issues before merging","If violations persist as a library bug, file with the specific rows from dolt_constraint_violations"],"exampleFix":"// inspect and clean\nrows := query(\"SELECT `table`, id FROM dolt_constraint_violations\")\n// delete orphaned dependents, e.g.:\ndb.Exec(\"DELETE FROM issue_labels WHERE issue_id NOT IN (SELECT id FROM issues)\")\n// then retry the merge","handlingStrategy":"fallback","validationCode":"rows, _ := db.QueryContext(ctx, \"SELECT \\\"table\\\", id FROM dolt_constraint_violations\")\n// if non-empty before merge, clean up first\n","typeGuard":null,"tryCatchPattern":"_, err := MergeWithStrategy(ctx, db, ref, \"ours\", author)\nif err != nil && strings.Contains(err.Error(), \"constraint violations\") {\n    // manual remediation:\n    // DELETE orphaned dependents or restore missing parents,\n    // verify dolt_constraint_violations is empty, then retry merge\n}","preventionTips":["Run FK-integrity cleanup (remove dependents of deleted issues) before merging","Prefer strategies that keep referential consistency for parent tables","Monitor dolt_constraint_violations after every strategy-resolved merge"],"tags":["dolt","merge","foreign-key","constraint-violation"],"backgroundTag":"dolt-constraint-violations-unresolved","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}