{"record":{"id":"b8425f3463bd9e37","repo":"gastownhall/beads","slug":"clear-conflict-for-issue-v-w","errorCode":null,"errorMessage":"clear conflict for issue %v: %w","messagePattern":"clear conflict for issue (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/versioncontrolops/automerge.go","lineNumber":624,"sourceCode":"\t\t\t// clearing the conflict now would discard their side undetectably.\n\t\t\t// But RowsAffected is rows CHANGED, not rows MATCHED: the DSN does\n\t\t\t// not set clientFoundRows (doltutil/dsn.go), so a write the backend\n\t\t\t// normalizes to the bytes already stored also reports zero. Only a\n\t\t\t// follow-up existence check can tell \"vanished\" from \"no-op\".\n\t\t\tif n, err := res.RowsAffected(); err != nil || n == 0 {\n\t\t\t\tpresent, err := conflictTargetStillPresent(ctx, db, \"issues\", issuesKeyColumn, m.ourKey)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"confirm issue %v still exists after writing merged values: %w\", m.ourKey, err)\n\t\t\t\t}\n\t\t\t\tif !present {\n\t\t\t\t\treturn fmt.Errorf(\"merged values for issue %v matched no row (was it deleted concurrently?); conflict left unresolved\", m.ourKey)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tres, err := db.ExecContext(ctx,\n\t\t\t\"DELETE FROM dolt_conflicts_issues WHERE our_\"+issuesKeyColumn+\" = ?\", m.ourKey)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"clear conflict for issue %v: %w\", m.ourKey, err)\n\t\t}\n\t\tif n, err := res.RowsAffected(); err == nil && n == 0 {\n\t\t\treturn fmt.Errorf(\"conflict for issue %v was not cleared (no conflict row deleted)\", m.ourKey)\n\t\t}\n\t}\n\treturn nil\n}\n\n// unionConflictsAreSafe reports whether every live conflict of a union-merged\n// table (labels, comments, events) is the same row on both sides with matching\n// columns — the only class where \"union\" has an unambiguous answer. A row\n// missing on one side (a deletion racing an insert) or diverging columns in a\n// supposedly immutable row goes to the operator.\nfunc unionConflictsAreSafe(ctx context.Context, db DBConn, table string) ([]unionRowKey, bool, error) {\n\tkeyCols, ok := unionConflictKeyColumns[table]\n\tif !ok {\n\t\treturn nil, false, fmt.Errorf(\"table %s is not union-mergeable\", table)\n\t}","sourceCodeStart":606,"sourceCodeEnd":642,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/versioncontrolops/automerge.go#L606-L642","documentation":"The merged values were written successfully, but the DELETE from dolt_conflicts_issues that marks the row as settled failed with a driver/database error. The delete is what tells Dolt the conflict is resolved, so the merge cannot proceed: the UPDATE has been applied but the conflict row remains, leaving the merge in a partially-resolved state reported by this wrapped error.","triggerScenarios":"db.ExecContext on `DELETE FROM dolt_conflicts_issues WHERE our_<key> = ?` fails — connection dropped after the UPDATE, the dolt_conflicts_issues system table is locked or unwritable (e.g. conflict metadata not flushed), the database entered a read-only state, or the dolt version in use rejects writes to conflict tables at that point in the merge.","commonSituations":"Remote Dolt server connection dies mid-resolution; another session concurrently manipulating conflicts locks the table; running a newer/older dolt version whose conflict-table semantics differ; transaction aborted by a concurrent schema change between UPDATE and DELETE.","solutions":["Re-run the merge/auto-resolve: the plan is recomputed from the (still-present) conflict row and both UPDATE and DELETE are re-executed idempotently.","Verify the Dolt server is reachable and supports the manual conflict-resolution path (`dolt version`, upgrade if old).","Check for competing `bd` processes touching the same database; serialize them and retry.","If the connection user lacks DELETE privilege on dolt_conflicts_issues, grant it or run the merge with an account that has it.","As a last resort, resolve the conflict manually via DOLT_CONFLICTS_RESOLVE for the issues table."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// confirm conflict tables are writable before starting resolution\n_, err := db.ExecContext(ctx,\n    \"SELECT COUNT(*) FROM dolt_conflicts_issues LIMIT 1\")\nif err != nil {\n    return fmt.Errorf(\"conflict table unreadable before merge: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"if err := TryAutoResolveMergeConflicts(ctx, db); err != nil {\n    if strings.Contains(err.Error(), \"clear conflict for issue\") {\n        // partial resolution: values written, conflict row remains — safe to retry\n        time.Sleep(time.Second)\n        return TryAutoResolveMergeConflicts(ctx, db)\n    }\n    return err\n}","preventionTips":["Ensure DELETE privileges on dolt_conflicts_issues for the merge user","Use a current dolt version; old servers may reject conflict-table writes at certain merge phases","Do not stop the Dolt server between the UPDATE and DELETE phases of resolution","Retry auto-resolution — it is idempotent because the conflict row still drives the plan"],"tags":["database","dolt","merge-conflict","conflict-table","partial-resolution"],"backgroundTag":"sql-delete-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}