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, nil

View on GitHub (pinned to 71377f2769)

Solutions

  1. Read the wrapped cause to see whether it was a timeout, cancellation, or SQL error.
  2. 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.
  3. Increase the query timeout or shrink the batch size if the recompute is timing out on big merges.
  4. If is_blocked values look wrong afterward, run the store's recompute/repair path manually.
  5. 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

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


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/54926741470a24bf. Report an issue: GitHub.