gastownhall/beads · error
pull from %s: %w
Error message
pull from %s: %w
What it means
Returned when the actual Dolt pull/merge operation against a peer fails with an error that is NOT a MergeConflictsError. Conflicts are captured and returned as data; anything else (network failure to the peer remote, auth failure, missing remote, merge implementation error) is wrapped here with the peer name for context.
Source
Thrown at internal/storage/embeddeddolt/version_control.go:653
if _, err := s.CommitPending(ctx, "beads"); err != nil {
return nil, fmt.Errorf("commit pending before pull: %w", err)
}
preHead := s.preMergeHead(ctx)
var conflicts []storage.Conflict
err := s.withPeerAuth(ctx, peer, func(user string) error {
return s.withMutatingPinnedDBConn(ctx, func(db versioncontrolops.DBConn) error {
if pullErr := versioncontrolops.Pull(ctx, db, peer, s.branch, user); pullErr != nil {
// bd-578h9.15: the settle machinery aborts a merge it cannot
// auto-resolve before returning, so dolt_conflicts is already
// empty here; the conflicts arrive captured pre-abort inside
// MergeConflictsError instead.
var mce *versioncontrolops.MergeConflictsError
if errors.As(pullErr, &mce) {
conflicts = mce.Conflicts
return nil
}
return fmt.Errorf("pull from %s: %w", peer, pullErr)
}
return nil
})
})
if err != nil || len(conflicts) > 0 {
// Conflicted pulls skip the recompute: the operator resolves first,
// and the next sync picks the rows up.
return conflicts, err
}
if err := s.recomputeBlockedAfterPull(ctx, preHead); err != nil {
return conflicts, fmt.Errorf("pull succeeded but is_blocked recompute failed: %w", err)
}
return conflicts, nil
}
// preMergeHead reads the pre-pull HEAD for the post-merge is_blocked
// recompute (bd-6dnrw.3). Empty on failure, which degrades the recompute to a
// full pass instead of skipping the hook.View on GitHub (pinned to 71377f2769)
Solutions
- Verify the peer remote exists and its URL is correct before pulling
- Check network connectivity and credentials for the peer
- Run `bd doctor` / inspect the underlying wrapped error (%%w chain) for the root cause
- Retry after the peer is back online; investigate if the wrapped error persists
Defensive patterns
Strategy: retry
Validate before calling
// verify peer connectivity/remote before pulling
if _, err := os.Stat(peerPath); err != nil {
return fmt.Errorf("peer unreachable before pull: %%w", err)
} Try / catch
if err := store.PullFrom(ctx, peer); err != nil {
var mce *versioncontrolops.MergeConflictsError
if errors.As(err, &mce) { return handleConflicts(mce.Conflicts) }
return fmt.Errorf("transient pull failure, retry later: %%w", err)
} Prevention
- Verify peer remote URLs at setup time
- Monitor peer availability before scheduled syncs
- Check credentials/keys for peer auth regularly
When it happens
Trigger: PullFrom(ctx, peer) and the inner withPeerAuth/withMutatingPinnedDBConn pull returns a non-conflict error: peer remote unreachable, invalid credentials, unknown remote name, or an unexpected dolt merge failure.
Common situations: Peer URL misconfigured or peer offline during sync; revoked or expired peer credentials; database not registered as a remote; Dolt version mismatch producing merge engine errors.
Related errors
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/9c22969d316e7da5.
Report an issue: GitHub.