{"record":{"id":"028cd148fd937c9f","repo":"gastownhall/beads","slug":"conflict-check-w","errorCode":null,"errorMessage":"conflict check: %w","messagePattern":"conflict check: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/bd/sync.go","lineNumber":251,"sourceCode":"// can land in the working set without moving it at all (bd-6dnrw.39). Anyone\n// revisiting the cost of this pass must start from storage.StateHasher and the\n// pending-recompute marker, not from HEAD.\n//\n// Returns (outcome, nil) for every outcome the caller maps to an exit code, and\n// (outcome, err) only for genuine failures (exit 1).\nfunc runSyncLoop(ctx context.Context, ops syncOps, maxAttempts int) (*syncOutcome, error) {\n\tif maxAttempts < 1 {\n\t\tmaxAttempts = 1\n\t}\n\tout := &syncOutcome{Status: syncStatusOK}\n\tvar evidence dirtyEvidence\n\n\t// Pre-flight. A previous halted sync leaves its conflicts live, and Dolt\n\t// refuses to merge over them — without this check that shows up as an\n\t// opaque pull failure (exit 1) instead of the conflict it actually is.\n\tpreConflicts, err := ops.conflicts(ctx)\n\tif err != nil {\n\t\treturn out, fmt.Errorf(\"conflict check: %w\", err)\n\t}\n\tif len(preConflicts) > 0 {\n\t\tout.Status = syncStatusConflict\n\t\tout.Conflicts = preConflicts\n\t\tout.ConflictsPreexisting = true\n\t\t// These came from the live conflict rows by definition, so a consumer\n\t\t// asking \"is this database conflicted right now\" gets a straight yes.\n\t\tout.ConflictsLive = true\n\t\treturn out, nil\n\t}\n\n\tfor attempt := 1; attempt <= maxAttempts; attempt++ {\n\t\t// A push race re-enters the loop; honor cancellation between attempts\n\t\t// so ^C or a timer's deadline is not swallowed by the retry budget.\n\t\tif err := ctx.Err(); err != nil {\n\t\t\treturn out, err\n\t\t}\n\t\tout.Attempts = attempt","sourceCodeStart":233,"sourceCodeEnd":269,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/sync.go#L233-L269","documentation":"Pre-flight conflict check in runSyncLoop: ops.conflicts(ctx) failed, so the loop cannot tell whether a previous sync left live merge conflicts. Sync is halted before pull because Dolt refuses to merge over live conflicts and this would otherwise surface as an opaque pull exit-1.","triggerScenarios":"The conflicts query itself errors — Dolt server unavailable, dolt_conflicts tables unreadable, or the storage driver returns an error while listing conflict rows at loop start.","commonSituations":"Dolt SQL server not running or wrong port; DB file permissions; a crashed prior sync left the repository in a state the conflicts query cannot read; driver/schema version mismatch after upgrading bd.","solutions":["Fix the underlying cause shown after 'conflict check:' (start Dolt server, fix permissions)","Resolve or clear leftover conflicts manually (dolt conflicts resolve / reset) then re-run sync","Run `bd doctor` to validate the database","Upgrade/align the bd and Dolt versions if the conflicts schema changed"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// pre-flight outside the tool: list live conflicts before syncing\ndolt sql -q \"SELECT * FROM dolt_conflicts\" || echo \"cannot read conflicts; fix Dolt first\"","typeGuard":null,"tryCatchPattern":"out, err := runSyncCommand(ctx, opts)\nif err != nil {\n    var conflictErr *ConflictCheckError\n    if errors.As(err, &conflictErr) {\n        // resolve leftover conflicts, then retry\n    }\n    return err\n}","preventionTips":["Always resolve/clear conflicts from a halted sync before the next `bd sync`","Avoid killing bd mid-sync (SIGKILL leaves conflict rows live)","Run `bd doctor` after any crashed sync","Keep a single writer process per DB at a time"],"tags":["go","sync","dolt","conflicts"],"backgroundTag":"sync-conflict-check-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}