{"record":{"id":"65521693bd3bc1be","repo":"gastownhall/beads","slug":"pull-succeeded-but-is-blocked-recompute-failed-w","errorCode":null,"errorMessage":"pull succeeded but is_blocked recompute failed: %w","messagePattern":"pull succeeded but is_blocked recompute failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/dolt/federation.go","lineNumber":165,"sourceCode":"\t\treturn nil\n\t}\n\tif c, conflictErr := s.GetConflicts(ctx); conflictErr == nil && len(c) > 0 {\n\t\t*conflicts = c\n\t\treturn nil\n\t}\n\treturn fmt.Errorf(\"failed to pull from peer %s: %w\", peer, pullErr)\n}\n\n// finishPeerPull runs the post-merge is_blocked recompute (bd-6dnrw.3) after a\n// successful, conflict-free peer pull and passes the pull result through\n// otherwise. Conflicted pulls skip the recompute: the caller resolves the\n// conflicts first, and the next sync picks the rows up.\nfunc (s *DoltStore) finishPeerPull(ctx context.Context, conflicts []storage.Conflict, pullErr error, preHead string) ([]storage.Conflict, error) {\n\tif pullErr != nil || len(conflicts) > 0 || s.readOnly {\n\t\treturn conflicts, pullErr\n\t}\n\tif err := s.recomputeBlockedAfterPull(ctx, preHead); err != nil {\n\t\treturn conflicts, fmt.Errorf(\"pull succeeded but is_blocked recompute failed: %w\", err)\n\t}\n\treturn conflicts, nil\n}\n\n// Fetch fetches refs from a peer without merging.\n// If credentials are stored for this peer, they are used automatically.\n// For git-protocol remotes, uses CLI `dolt fetch` to avoid MySQL connection timeouts.\nfunc (s *DoltStore) Fetch(ctx context.Context, peer string) error {\n\tif useCLI, err := s.prepareCLIRouteForPeerGitProtocol(ctx, peer); err != nil {\n\t\treturn err\n\t} else if useCLI {\n\t\treturn s.withPeerCredentials(ctx, peer, func(creds *remoteCredentials) error {\n\t\t\treturn s.doltCLIFetchFromPeer(ctx, peer, creds)\n\t\t})\n\t}\n\treturn s.withPeerCredentials(ctx, peer, func(creds *remoteCredentials) error {\n\t\t// Credential CLI routing: route fetch through CLI subprocess.\n\t\tif useCLI, err := s.prepareCLIRouteForPeerCredentials(ctx, peer, creds); err != nil {","sourceCodeStart":147,"sourceCodeEnd":183,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/dolt/federation.go#L147-L183","documentation":"The peer pull itself succeeded and produced no conflicts, but the post-merge is_blocked recompute (recomputeBlockedAfterPull) failed. finishPeerPull wraps that recompute error so the caller knows the data was pulled but derived is_blocked fields may be stale. This is a consistency error, not a data-loss error.","triggerScenarios":"PullFrom completes a clean pull on a writable store (not readOnly, no conflicts), then recomputeBlockedAfterPull(ctx, preHead) returns an error — typically a SQL failure while recomputing blocked-issue state over the merge diff.","commonSituations":"Database under load or locked during a long sync; SQL timeout during the recompute; schema drift between replicas affecting the blocked-recompute query; read-only/store contention after automated pulls.","solutions":["Inspect the wrapped cause (%w chain) — it names the failing recompute query/statement","Re-run a sync after the transient DB issue clears; the recompute is idempotent over the merge window","Manually trigger the blocked recompute (or next sync) to refresh is_blocked values","Check dolt server logs for the failing statement around the pull timestamp"],"exampleFix":"// before: treating as fatal pull failure\nclose(stCh)\n// after: treat pull as done, schedule recompute retry\nconflicts, err := store.PullFrom(ctx, peer)\nif err != nil && strings.Contains(err.Error(), \"is_blocked recompute failed\") {\n    log.Warnf(\"pulled but recompute failed, will retry: %v\", err)\n}","handlingStrategy":"retry","validationCode":"if store == nil || storeIsReadOnly() { skipPullRecomputeExpectations() }","typeGuard":"func isRecomputeFailure(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"is_blocked recompute failed\")\n}","tryCatchPattern":"conflicts, err := store.PullFrom(ctx, peer)\nif isRecomputeFailure(err) {\n    log.Warn(\"pull ok, recompute failed; retrying later\")\n    scheduleRecompute()\n    err = nil\n}","preventionTips":["Schedule periodic consistency recompute so a missed one self-heals","Avoid running syncs during heavy DB load or backup windows","Monitor the wrapped cause for recurring SQL timeouts and tune server timeouts"],"tags":["dolt","federation","recompute","consistency"],"backgroundTag":"post-merge-recompute-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}