gastownhall/beads · error
pull succeeded but is_blocked recompute failed: %w
Error message
pull succeeded but is_blocked recompute failed: %w
What it means
After a successful pull, a writable store recomputes the denormalized is_blocked column for rows the merge touched. This error is raised when the pull itself landed fine but that post-merge recompute failed. The data is merged but derived dependency state may be stale or inconsistent until the recompute succeeds.
Source
Thrown at internal/storage/dolt/store.go:4032
preHead = h
}
if err := s.pullTransport(ctx, remote); err != nil {
return err
}
// ga-ivaps: a route that returns nil having merged nothing is silent
// divergence, so a transport's own "success" is not taken as proof the
// merge landed. Checked before the recompute: recomputing derived state
// over a merge that never arrived would report a second success on top of
// the first.
if err := s.verifyPullLanded(ctx, remote, preHead); err != nil {
return err
}
if !s.readOnly {
if err := s.recomputeBlockedAfterPull(ctx, preHead); err != nil {
return fmt.Errorf("pull succeeded but is_blocked recompute failed: %w", err)
}
}
return nil
}
// branchHash returns the commit hash at the tip of a local branch, or the empty
// string when the branch has no row. Reads dolt_branches, which is global to the
// database, so the answer does not depend on which branch the pooled connection
// happens to be sitting on.
func (s *DoltStore) branchHash(ctx context.Context, branch string) (string, error) {
var hash string
if err := s.db.QueryRowContext(ctx, "SELECT hash FROM dolt_branches WHERE name = ?", branch).Scan(&hash); err != nil {
if errors.Is(err, sql.ErrNoRows) {
return "", nil
}
return "", err
}
return hash, nilView on GitHub (pinned to 71377f2769)
Solutions
- Read the wrapped cause to see whether it was a timeout, cancellation, or SQL error.
- Re-run the pull or a recompute pass — the merge already landed, so a retry of the pull is a no-op and the recompute will run again.
- Increase the query timeout or shrink the batch size if the recompute is timing out on big merges.
- If is_blocked values look wrong afterward, run the store's recompute/repair path manually.
- Check sql-server health if the cause was a connection failure.
Example fix
// before
err := store.Pull(ctx)
// after
if err != nil && strings.Contains(err.Error(), "is_blocked recompute failed") {
// merge landed; only derived state is stale — re-pull to retrigger recompute
err = store.Pull(ctx)
} Defensive patterns
Strategy: retry
Validate before calling
if err := ctx.Err(); err != nil { return err } // ensure context is live before pulling Try / catch
if err := store.Pull(ctx); err != nil {
if strings.Contains(err.Error(), "is_blocked recompute failed") {
// merge already landed; re-pull to retrigger only the recompute
return store.Pull(ctx)
}
return err
} Prevention
- Use generous context timeouts for pulls of large dependency graphs.
- Verify is_blocked values after big merges if you consume them directly.
- Keep the sql-server healthy so recompute queries don't drop.
- Watch for repeated recompute failures — investigate the wrapped SQL error rather than blind-retrying.
When it happens
Trigger: Pull()/PullRemote() on a writable store where recomputeBlockedAfterPull fails after verifyPullLanded succeeded: the recompute UPDATE/dependency-walk errors out (connection timeout, context deadline, SQL error) against s.db.
Common situations: Large merges touching many dependent issues exceed the pool's ~10s read timeout; the context was cancelled mid-recompute; a trigger or constraint rejects the is_blocked UPDATE; the sql-server was restarted between the merge and the recompute.
Related errors
- failed to commit pending changes before pull: %w
- failed to pull from peer %s: %w
- pull succeeded but is_blocked recompute failed: %w
- conflicts resolved but is_blocked recompute failed: %w
- inspect dirty config before pull: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/54926741470a24bf.
Report an issue: GitHub.