gastownhall/beads · error

merge succeeded but is_blocked recompute failed: %w

Error message

merge succeeded but is_blocked recompute failed: %w

What it means

Merge completed successfully (no merge errors and no conflicts) in a non-read-only store, but the follow-up recompute of the denormalized is_blocked column (recomputeBlockedAfterPull) failed. The merge itself is durable; only the derived blocked-status data may be stale, so the error is reported as a post-merge failure with the original conflicts still returned alongside it.

Source

Thrown at internal/storage/embeddeddolt/version_control.go:315

func (s *EmbeddedDoltStore) Merge(ctx context.Context, branch string) ([]storage.Conflict, error) {
	// bd-578h9.11: like every pull path, a branch merge brings in writes that
	// bypassed the local is_blocked hooks; recompute after a conflict-free
	// merge. Conflicted merges defer to the caller's post-resolution hook
	// (Sync, bd vc merge --strategy) — recomputing over unresolved rows would
	// read garbage.
	preHead := ""
	if !s.readOnly {
		preHead = s.preMergeHead(ctx)
	}
	var conflicts []storage.Conflict
	err := s.withMutatingDBConn(ctx, func(db versioncontrolops.DBConn) error {
		var err error
		conflicts, err = versioncontrolops.Merge(ctx, db, branch, commitAuthor)
		return err
	})
	if err == nil && len(conflicts) == 0 && !s.readOnly {
		if rerr := s.recomputeBlockedAfterPull(ctx, preHead); rerr != nil {
			return conflicts, fmt.Errorf("merge succeeded but is_blocked recompute failed: %w", rerr)
		}
	}
	return conflicts, err
}

// MergeWithStrategy implements storage.StrategicMerger for `bd vc merge
// --strategy` (#4992). Unlike Merge, it runs on a PINNED session
// (withMutatingPinnedDBConn, not withMutatingDBConn): the conflict-tolerant
// session flags versioncontrolops.MergeWithStrategy sets are session state
// and must be visible to the merge, resolve, repair, and commit statements
// that follow — a *sql.DB pool (OpenSQL allows 2 idle conns) could otherwise
// hand out a different connection mid-sequence.
//
// A resolved merge (conflicted or clean) always commits, so — unlike plain
// Merge, which skips the recompute for a still-conflicted merge — the
// is_blocked recompute always runs on success here.
func (s *EmbeddedDoltStore) MergeWithStrategy(ctx context.Context, branch, strategy string) ([]storage.Conflict, error) {
	preHead := ""

View on GitHub (pinned to 71377f2769)

Solutions

  1. Read the wrapped rerr for the recompute failure cause (SQL error, context cancelled, connection loss) and address that root cause.
  2. Re-run the recompute to refresh is_blocked — rerunning Sync/merge (which will be a no-op merge) or a dedicated recompute path restores consistency.
  3. If the context was cancelled, retry with a longer deadline so merge and recompute complete together.
  4. Check for schema drift on the issues table (is_blocked column) and apply any pending migrations before retrying.
  5. Verify data consistency manually if is_blocked values look stale: the merge succeeded, only derived columns may be outdated.

Example fix

// before: ignoring post-merge recompute need
conflicts, err := store.Merge(ctx, branch, author)

// after: recover from recompute failure explicitly
conflicts, err := store.Merge(ctx, branch, author)
if err != nil && strings.Contains(err.Error(), "is_blocked recompute failed") {
    // merge landed; re-run to refresh derived state
    _, err = store.Sync(ctx)
}
Defensive patterns

Strategy: try-catch

Try / catch

conflicts, err := store.Merge(ctx, branch, author)
if err != nil {
    if strings.Contains(err.Error(), "is_blocked recompute failed") {
        // merge landed durably; only derived state is stale.
        // process conflicts normally, then trigger a recompute/sync.
        _ = refreshBlockedStatus(ctx)
    }
    return conflicts, err
}

Prevention

When it happens

Trigger: Calling Merge (used by Sync) on an EmbeddedDoltStore where the merge succeeds but recomputeBlockedAfterPull errors — e.g. the recompute SQL fails, the pinned connection is lost mid-recompute, or the context is cancelled between merge and recompute.

Common situations: Network-triggered sync where the context times out right after the merge; database contention during the recompute query; schema/driver errors in the denormalized is_blocked update after schema drift or partial migration.

Related errors


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