gastownhall/beads · error
conflict resolution failed for %s: %w
Error message
conflict resolution failed for %s: %w
What it means
Sync attempted to auto-resolve each conflict via ResolveConflicts(ctx, c.Field, strategy) and one of those calls failed. The error names the offending field (%s) and wraps the cause. Resolution is per-field, so partial resolution may have occurred for earlier fields.
Source
Thrown at internal/storage/dolt/federation.go:394
if err != nil {
result.Error = fmt.Errorf("merge failed: %w", err)
return result, result.Error
}
// Step 4: Handle conflicts if any
if len(conflicts) > 0 {
result.Conflicts = conflicts
if strategy == "" {
// No strategy specified, leave conflicts for manual resolution
result.Error = fmt.Errorf("merge conflicts require resolution (use --strategy ours|theirs)")
return result, result.Error
}
// Auto-resolve using strategy
for _, c := range conflicts {
if err := s.ResolveConflicts(ctx, c.Field, strategy); err != nil {
result.Error = fmt.Errorf("conflict resolution failed for %s: %w", c.Field, err)
return result, result.Error
}
}
result.ConflictsResolved = true
// Commit the resolution INCLUDING config: the operator chose this
// strategy, and plain Commit excludes config (GH#2455). A config-only
// conflict — routine now that kv.memory.* memories sync through config —
// would otherwise resolve but never commit, leaving the merge
// unconcluded and re-wedging the next sync.
if err := s.CommitMergeResolution(ctx, fmt.Sprintf("Resolve conflicts from %s using %s strategy", peer, strategy)); err != nil {
result.Error = fmt.Errorf("failed to commit conflict resolution: %w", err)
return result, result.Error
}
// bd-578h9.11: the conflicted merge skipped the automatic is_blocked
// recompute (unresolved rows would have fed it garbage); now that the
// resolution is committed, cover the whole merge+resolution window.View on GitHub (pinned to 71377f2769)
Solutions
- Note the named field and inspect `dolt conflicts` / result.Conflicts for its state
- Re-run the sync with the same strategy — resolution is re-attempted per remaining conflict
- Check for concurrent processes touching dolt_conflicts and serialize syncs
- Verify the strategy is exactly "ours" or "theirs" and the local schema matches the peer's
- If schema drift is the cause, pull the peer's schema changes first (fetch+merge on a clean tree)
Defensive patterns
Strategy: try-catch
Validate before calling
if strategy != "ours" && strategy != "theirs" {
return fmt.Errorf("strategy must be ours|theirs, got %q", strategy)
} Try / catch
result, err := store.Sync(ctx, peer, strategy, opts)
if err != nil && strings.Contains(err.Error(), "conflict resolution failed for") {
field := extractField(err) // parse %s from message or read result.Conflicts
log.Printf("resolution failed on field %s; retrying sync", field)
retrySync(strategy)
} Prevention
- Keep both replicas on the same schema version before syncing
- Serialize syncs so conflict rows aren't mutated concurrently
- Validate strategy strings at the CLI boundary
When it happens
Trigger: store.Sync(ctx, peer, "ours"|"theirs", opts) where a conflicted merge exists and ResolveConflicts errors on some field — e.g. the field no longer exists, SQL failure writing the resolution, or strategy value invalid at the storage layer.
Common situations: Schema drift between replicas so a conflicted field is unknown locally; DB lock/timeout mid-resolution; strategy string corrupted before reaching the store; conflict rows already cleaned up by a concurrent process.
Related errors
- merge conflicts require resolution (use --strategy ours|thei
- failed to commit conflict resolution: %w
- failed to commit pending changes before sync: %w
- fetch failed: %w
- merge failed: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/f27db57eadd81f10.
Report an issue: GitHub.