gastownhall/beads · critical

pull from %s/%s reported success but merged nothing into %s:

Error message

pull from %s/%s reported success but merged nothing into %s: %s is at %s while %s is at %s (their common ancestor is %s), so the commits on the remote-tracking ref are not on the branch this database reads. Most often another client pushed after this pull fetched and a re-run will merge it; if the divergence survives repeated re-runs, the transport is not landing merges on this branch (for example the dolt CLI directory and the sql-server are serving different databases or branches)

What it means

This store verifies that a pull actually merged the fetched commits into the branch the database reads (via DOLT_MERGE_BASE containment against the refreshed remote-tracking ref). This error fires when the transport reported success but the local branch does not contain the tracking ref — i.e., the merge landed nowhere the caller reads. It names both tips and their merge base so the developer can diagnose divergence.

Source

Thrown at internal/storage/dolt/store.go:4187

	//     nothing", so a caller that surfaces it reads the same diagnosis.
	//   - otherwise: local and the tracking ref have genuinely diverged (their
	//     common ancestor is neither tip), which no re-pull can fast-forward away.
	//     That is the stuck-transport / split-brain signal, and it stays a hard
	//     error.
	//
	// The split fails safe: a true divergence can never be demoted to the
	// retryable class, because its common ancestor is by definition neither tip.
	// Distinguishing the benign race from a genuinely failed transport would
	// still need the remote tip as of the transport's own fetch, which git-backed
	// remotes never write into this database; the merge base is the best post-hoc
	// split available. Classified before the display fallback below rewrites an
	// empty localHash.
	behindFastForwardable := localHash != "" && mergeBase.String == localHash

	if localHash == "" {
		localHash = "unknown"
	}
	mergedNothing := fmt.Errorf("pull from %s/%s reported success but merged nothing into %s: %s is at %s while %s is at %s "+
		"(their common ancestor is %s), so the commits on the remote-tracking ref are not on the branch this "+
		"database reads. Most often another client pushed after this pull fetched and a re-run will merge it; "+
		"if the divergence survives repeated re-runs, the transport is not landing merges on this branch "+
		"(for example the dolt CLI directory and the sql-server are serving different databases or branches)",
		remote, s.branch, s.branch, s.branch, localHash, trackingRef, remoteHash, mergeBase.String)
	if behindFastForwardable {
		return fmt.Errorf("%w: %w", versioncontrolops.ErrPullBehindFastForwardable, mergedNothing)
	}
	return mergedNothing
}

// refreshTrackingRef fetches remote/s.branch into this database's
// remote-tracking refs over a dedicated long-timeout, credential-aware
// connection, so verifyPullLanded's comparison reads a tracking ref this
// database just wrote. It mirrors pullTransport's own network calls: a
// long-timeout connection (openLongTimeoutConn) wrapped in the remote's
// credential/S3 environment (withRemoteOperationEnv), which is what lets the
// refresh reach CLI-routed (git-protocol, credential, cloud-auth) remotes that

View on GitHub (pinned to 71377f2769)

Solutions

  1. Re-run the pull — if it was a push race, the next pull fast-forwards and the error disappears.
  2. If it persists, confirm the dolt CLI working directory and the sql-server are serving the same database and branch as this store's connection string.
  3. Compare the hashes in the message (branch tip vs tracking ref vs merge base) to see whether the branch is an ancestor (retryable) or diverged.
  4. Restart the sql-server so cached git-blobstore mirrors re-sync if the remote is git-backed.
  5. Inspect `dolt branch -a` / dolt_remote_branches in the actual database this store connects to.

Example fix

// before
// persistent failure: CLI in /srv/bd, sql-server serving /var/lib/dolt/bd
// after
// point both at the same database dir, or configure the store to use the
// sql-server's own DSN exclusively:
store, err := OpenDoltStore("dolt://user@tcp(localhost:3307)/bd?branch=main")
Defensive patterns

Strategy: retry

Validate before calling

// before pulling, confirm CLI dir and sql-server serve the same db/branch:
// dolt branch --current  (in the CLI workdir)  vs  store's configured branch

Try / catch

if err := store.Pull(ctx); err != nil {
    var mergedNothingErr *fmt.wrapError // or match on message
    if strings.Contains(err.Error(), "reported success but merged nothing") &&
        !errors.Is(err, versioncontrolops.ErrPullBehindFastForwardable) {
        // genuine divergence: reconfigure transports / restart sql-server before retrying
    }
    return err
}

Prevention

When it happens

Trigger: The pull transport (dolt CLI subprocess or CALL DOLT_PULL on a sql-server) operated against a different database/branch/directory than the one this store reads; or a peer pushed to the remote after this pull fetched, leaving the branch strictly behind (that variant is wrapped in ErrPullBehindFastForwardable, error 2703).

Common situations: The dolt CLI runs in one working directory while the sql-server serves another database or branch (split-brain config); another clone pushed mid-pull; a git-blobstore-backed remote inside its 1s read-sync TTL window; PullRemote targeting a federation peer whose merge lands on a default branch instead of s.branch.

Related errors


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