{"record":{"id":"aa75a8f41795e8cc","repo":"gastownhall/beads","slug":"conflicts-resolved-but-is-blocked-recompute-failed-aa75a8","errorCode":null,"errorMessage":"conflicts resolved but is_blocked recompute failed: %w","messagePattern":"conflicts resolved but is_blocked recompute failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/embeddeddolt/federation.go","lineNumber":359,"sourceCode":"\t\t}\n\t\tresult.ConflictsResolved = true\n\n\t\t// CommitMergeResolution, not Commit: Commit's GH#3886 nothing-to-commit\n\t\t// tolerance would swallow the --ours case (resolution dirties nothing)\n\t\t// as a silent no-op here, leaving dolt_merge_status.is_merging true while\n\t\t// this function reports result.Merged = true and pushes — the exact\n\t\t// re-wedge CommitMergeResolution's doc comment describes. See the\n\t\t// server-mode twin, dolt/federation.go's Sync.\n\t\tif err := s.CommitMergeResolution(ctx, fmt.Sprintf(\"Resolve conflicts from %s using %s strategy\", peer, strategy)); err != nil {\n\t\t\tresult.Error = fmt.Errorf(\"commit conflict resolution: %w\", err)\n\t\t\treturn result, result.Error\n\t\t}\n\n\t\t// bd-578h9.11: the conflicted merge skipped the automatic is_blocked\n\t\t// recompute (unresolved rows would have fed it garbage); now that the\n\t\t// resolution is committed, cover the whole merge+resolution window.\n\t\tif err := s.RecomputeBlockedAfterMerge(ctx, beforeCommit); err != nil {\n\t\t\tresult.Error = fmt.Errorf(\"conflicts resolved but is_blocked recompute failed: %w\", err)\n\t\t\treturn result, result.Error\n\t\t}\n\t}\n\tresult.Merged = true\n\n\tafterCommit, _ := s.GetCurrentCommit(ctx)\n\tif beforeCommit != afterCommit {\n\t\tresult.PulledCommits = 1\n\t}\n\n\t// Step 5: Push\n\tif err := s.PushTo(ctx, peer); err != nil {\n\t\tresult.PushError = err\n\t} else {\n\t\tresult.Pushed = true\n\t}\n\n\t// Record last sync time in metadata.","sourceCodeStart":341,"sourceCodeEnd":377,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/embeddeddolt/federation.go#L341-L377","documentation":"A conflicted merge skips the automatic is_blocked recompute (unresolved rows would feed it garbage), so once the resolution is committed, Sync calls RecomputeBlockedAfterMerge(ctx, beforeCommit) to cover the whole merge+resolution window (bd-578h9.11). Failure here is wrapped as this error: conflicts are resolved and committed, but the blocked-status derived data may be stale.","triggerScenarios":"store.Sync(ctx, peer, strategy) completing conflict resolution successfully, then RecomputeBlockedAfterMerge errors — SQL failure during the recompute, a dependency-cycle detection error, or the transaction touching rows mutated concurrently.","commonSituations":"Large merge with many dependency edges making the recompute slow or resource-constrained; concurrent writer modifying dependencies mid-recompute; pre-existing bad dependency rows that trip cycle validation.","solutions":["Manually trigger the blocked recompute (e.g. via the admin/doctor path) to refresh is_blocked.","Re-run sync — the recompute is idempotent once the resolution is committed.","Inspect dependency rows introduced by the merge for cycles or dangling references.","Verify is_blocked values manually if the recompute keeps failing and file an issue."],"exampleFix":"// before: stale is_blocked after a failed recompute\nresult, err := store.Sync(ctx, peer, \"ours\")\n// after: force a recompute if sync reports the failure\nresult, err := store.Sync(ctx, peer, \"ours\")\nif err != nil && strings.Contains(err.Error(), \"is_blocked recompute failed\") {\n    if rerr := store.RecomputeBlocked(ctx); rerr == nil {\n        err = nil // derived data repaired; merge itself succeeded\n    }\n}","handlingStrategy":"fallback","validationCode":"// sanity-check dependency rows the merge will introduce\nfor _, dep := range incomingDeps {\n    if dangling(dep) || cycleWouldForm(dep) {\n        return fmt.Errorf(\"fix dependency %s before sync\", dep)\n    }\n}","typeGuard":null,"tryCatchPattern":"result, err := store.Sync(ctx, peer, \"ours\")\nif err != nil && strings.Contains(err.Error(), \"is_blocked recompute failed\") {\n    // merge itself succeeded; repair derived data out-of-band\n    if rerr := store.RecomputeBlocked(ctx); rerr == nil {\n        err = nil\n    }\n}","preventionTips":["Periodically recompute is_blocked even outside merges.","Guard against dependency cycles in write paths.","Avoid concurrent dependency edits during sync windows.","Alert on recompute failures — stale is_blocked silently misroutes work."],"tags":["sync","derived-data","dependencies"],"backgroundTag":"recompute-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}