{"record":{"id":"bf390f12c6b16432","repo":"gastownhall/beads","slug":"no-live-conflict-for-s-s","errorCode":null,"errorMessage":"no live conflict for %s %s","messagePattern":"no live conflict for (.+?) (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/storage/versioncontrolops/conflicts.go","lineNumber":321,"sourceCode":"// either side's key column so a row only one side has is *found* and then\n// refused with a precise message, rather than reported as \"no conflict\".\nfunc loadConflictRow(ctx context.Context, db DBConn, table, keyCol, key string) (rawConflictRow, error) {\n\tq := fmt.Sprintf(\"SELECT * FROM `dolt_conflicts_%s` WHERE `our_%s` = ? OR `their_%s` = ?\", table, keyCol, keyCol) //nolint:gosec // identifiers validated\n\trows, err := db.QueryContext(ctx, q, key, key)\n\tif err != nil {\n\t\treturn rawConflictRow{}, fmt.Errorf(\"query conflict for %s %s: %w\", table, key, err)\n\t}\n\tdefer func() { _ = rows.Close() }()\n\n\tcols, err := rows.Columns()\n\tif err != nil {\n\t\treturn rawConflictRow{}, fmt.Errorf(\"conflict columns for table %s: %w\", table, err)\n\t}\n\tif !rows.Next() {\n\t\tif err := rows.Err(); err != nil {\n\t\t\treturn rawConflictRow{}, fmt.Errorf(\"query conflict for %s %s: %w\", table, key, err)\n\t\t}\n\t\treturn rawConflictRow{}, fmt.Errorf(\"no live conflict for %s %s\", table, key)\n\t}\n\tvals := make([]any, len(cols))\n\tptrs := make([]any, len(cols))\n\tfor i := range vals {\n\t\tptrs[i] = &vals[i]\n\t}\n\tif err := rows.Scan(ptrs...); err != nil {\n\t\treturn rawConflictRow{}, fmt.Errorf(\"scan conflict for %s %s: %w\", table, key, err)\n\t}\n\tif rows.Next() {\n\t\treturn rawConflictRow{}, fmt.Errorf(\"multiple conflict rows for %s %s; resolve the whole table instead\", table, key)\n\t}\n\treturn rawConflictRow{cols: cols, vals: vals}, errors.Join(rows.Err(), rows.Close())\n}\n\n// conflictTargetStillPresent reports whether key still names a row of table.\n//\n// It is the matched-rows check the resolvers need after a write, because","sourceCodeStart":303,"sourceCodeEnd":339,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/versioncontrolops/conflicts.go#L303-L339","documentation":"loadConflictRow found no matching row in dolt_conflicts_<table> for the given key, so there is nothing to resolve at row level. This is thrown when the key no longer corresponds to a live conflict — usually because the conflict was already resolved (ours/theirs, or by the peer) between listing conflicts and resolving this one. It is a stale-list condition, not a data corruption.","triggerScenarios":"ResolveConflictRows iterates a previously fetched conflict list and calls loadConflictRow for a key whose conflict row has already been deleted by an earlier resolution, a concurrent session, or because the merge was aborted/committed in the meantime.","commonSituations":"Running two `bd conflicts --theirs` sessions concurrently; resolving conflicts in a UI/CLI that cached the list; re-running a partially completed resolution script that already settled some rows.","solutions":["Re-list the current conflicts (refresh the table view) and resolve only keys that still appear","Check whether another session or process resolved the conflict concurrently","If the merge was already committed or aborted, the conflict is gone — no action needed","Retry the whole resolution pass atomically instead of replaying a stale key list"],"exampleFix":"// before\nfor _, key := range staleKeys {\n    resolveOne(ctx, db, table, keyCol, key, strategy) // fails: no live conflict\n}\n// after\nkeys, err := listConflictKeys(ctx, db, table) // re-read live conflict rows\nfor _, key := range keys {\n    resolveOne(ctx, db, table, keyCol, key, strategy)\n}","handlingStrategy":"validation","validationCode":"// re-list live conflicts immediately before resolving each key\nkeys, err := listConflictKeys(ctx, db, table)\nif err != nil { return err }\nresolveSet := intersect(pendingKeys, keys)","typeGuard":null,"tryCatchPattern":"err := resolveOne(ctx, db, table, keyCol, key, strategy)\nif err != nil && strings.Contains(err.Error(), \"no live conflict for\") {\n    // already resolved elsewhere; refresh list and continue\n    return refreshAndContinue()\n}\nreturn err","preventionTips":["Resolve conflicts from a freshly fetched list, never a cached one","Run only one resolution session at a time per database","Make resolution scripts idempotent: skip keys no longer in conflict","Re-check merge state before and after batch resolution"],"tags":["database","dolt","stale-state","conflict-resolution"],"backgroundTag":"stale-conflict-row","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}