gastownhall/beads · error
failed to pull from peer %s: %w
Error message
failed to pull from peer %s: %w
What it means
This error wraps the underlying failure of a DOLT_PULL against a named peer remote. It is thrown by peerPullOutcome only when the pull failed with a real error — not a merge-conflict outcome (those are returned as data via MergeConflictsError or GetConflicts). The %w wrap preserves the root cause (network, auth, remote missing, etc.) for errors.Is/As inspection.
Source
Thrown at internal/storage/dolt/federation.go:153
// as data for the caller, anything else stays an error. The SQL route rolls
// the conflicted merge back before returning, so its conflicts arrive only via
// MergeConflictsError, captured pre-rollback (bd-578h9.15); the CLI route's
// subprocess writes conflicts to the on-disk working set where GetConflicts
// still sees them.
func (s *DoltStore) peerPullOutcome(ctx context.Context, peer string, pullErr error, conflicts *[]storage.Conflict) error {
if pullErr == nil {
return nil
}
var mce *versioncontrolops.MergeConflictsError
if errors.As(pullErr, &mce) {
*conflicts = mce.Conflicts
return nil
}
if c, conflictErr := s.GetConflicts(ctx); conflictErr == nil && len(c) > 0 {
*conflicts = c
return nil
}
return fmt.Errorf("failed to pull from peer %s: %w", peer, pullErr)
}
// finishPeerPull runs the post-merge is_blocked recompute (bd-6dnrw.3) after a
// successful, conflict-free peer pull and passes the pull result through
// otherwise. Conflicted pulls skip the recompute: the caller resolves the
// conflicts first, and the next sync picks the rows up.
func (s *DoltStore) finishPeerPull(ctx context.Context, conflicts []storage.Conflict, pullErr error, preHead string) ([]storage.Conflict, error) {
if pullErr != nil || len(conflicts) > 0 || s.readOnly {
return conflicts, pullErr
}
if err := s.recomputeBlockedAfterPull(ctx, preHead); err != nil {
return conflicts, fmt.Errorf("pull succeeded but is_blocked recompute failed: %w", err)
}
return conflicts, nil
}
// Fetch fetches refs from a peer without merging.
// If credentials are stored for this peer, they are used automatically.View on GitHub (pinned to 71377f2769)
Solutions
- Run `bd dolt pull <peer>` (or dolt fetch) manually against the peer URL to see the raw underlying error
- Verify the peer remote exists and its URL is reachable: `dolt remote -v`, then `dolt ls-remote <remote>`
- Refresh or re-add stored credentials for the peer so withPeerCredentials supplies valid auth
- If the pull rolled back due to divergence, pull with a resolve strategy or fetch+merge explicitly to surface conflicts
- Ensure the dolt binary is installed and on PATH when the CLI route is used
Example fix
// before: opaque failure
conflicts, err := store.PullFrom(ctx, "origin")
// after: pre-check remote and surface the wrapped cause
var targetErr *versioncontrolops.MergeConflictsError
if err != nil && !errors.As(err, &targetErr) {
log.Fatalf("peer pull failed: %v", err) // %w chain shows root cause
} Defensive patterns
Strategy: try-catch
Validate before calling
remotes, err := store.ListRemotes(ctx)
if err != nil || !containsRemote(remotes, peer) {
return fmt.Errorf("peer %q not configured; add it first", peer)
} Type guard
func isConflictOutcome(err error) bool {
var mce *versioncontrolops.MergeConflictsError
return errors.As(err, &mce)
} // if false and err != nil, it's a hard pull failure Try / catch
conflicts, err := store.PullFrom(ctx, peer)
var mce *versioncontrolops.MergeConflictsError
switch {
case err == nil:
// clean pull
case errors.As(err, &mce):
// handle conflicts as data
default:
return fmt.Errorf("peer pull %s unavailable: %w", peer, err)
} Prevention
- Verify the peer remote exists and is reachable before pulling (ListRemotes + ls-remote)
- Keep peer credentials fresh and test them with a cheap fetch
- Sync frequently to avoid non-fast-forward divergence that rolls merges back
- Ensure the dolt CLI is installed when relying on the CLI route
When it happens
Trigger: Calling PullFrom(ctx, peer) (or Sync's internal pull path) where DOLT_PULL or the CLI dolt pull exits with an error that is neither a MergeConflictsError nor leaves readable rows in dolt_conflicts — e.g. unknown remote, unreachable URL, bad credentials, non-fast-forward divergence.
Common situations: Peer URL points at a repo that was deleted or renamed; SSH/HTTPS credentials expired or absent; the peer branch diverged so the merge rolls back with no conflict rows (e.g. FK delete-vs-insert divergence noted in the code); dolt CLI binary missing when the CLI route is selected.
Related errors
- failed to push to peer %s: %w
- failed to commit pending changes before pull: %w
- failed to fetch from peer %s: %w
- fetch failed: %w
- pull from %s: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/a01c8b4b6d6a763f.
Report an issue: GitHub.