gastownhall/beads · error

fetch failed: %w

Error message

fetch failed: %w

What it means

Sync wraps any Fetch failure (see error 2522) with this prefix at Step 1 and aborts the sync. Nothing has been merged yet, so the database is unchanged; result.Fetched stays false. The wrapped cause carries the underlying fetch error.

Source

Thrown at internal/storage/dolt/federation.go:365

	}

	// GH#2474: match PullFrom — commit pending changes before the merge,
	// INCLUDING config (where kv.memory.* rows live). Plain Commit excludes
	// config (GH#2455), so federation metadata writes such as add-peer plus any
	// persistent memories would otherwise leave the working set dirty and wedge
	// DOLT_MERGE ("cannot merge with uncommitted changes").
	if !s.readOnly {
		if err := s.commitBeforePull(ctx, "auto-commit before sync"); err != nil {
			if !isDoltNothingToCommit(err) {
				result.Error = fmt.Errorf("failed to commit pending changes before sync: %w", err)
				return result, result.Error
			}
		}
	}

	// Step 1: Fetch from peer
	if err := s.Fetch(ctx, peer); err != nil {
		result.Error = fmt.Errorf("fetch failed: %w", err)
		return result, result.Error
	}
	result.Fetched = true

	// Step 2: Get status before merge
	beforeCommit, _ := s.GetCurrentCommit(ctx) // Best effort: empty commit hash means diff won't be logged

	// Step 3: Merge peer's branch
	remoteBranch := fmt.Sprintf("%s/%s", peer, s.branch)
	conflicts, err := s.Merge(ctx, remoteBranch)
	if err != nil {
		result.Error = fmt.Errorf("merge failed: %w", err)
		return result, result.Error
	}

	// Step 4: Handle conflicts if any
	if len(conflicts) > 0 {
		result.Conflicts = conflicts

View on GitHub (pinned to 71377f2769)

Solutions

  1. Read the wrapped cause (%w) to distinguish network vs auth vs unknown-remote
  2. Verify peer connectivity and remote config (`dolt remote -v`, `dolt ls-remote <peer>`)
  3. Refresh credentials for the peer and retry the sync
  4. Add retry/backoff around Sync for transient outages
  5. If SQL-route timeouts recur, ensure the CLI fetch route is used for git-protocol remotes
Defensive patterns

Strategy: retry

Validate before calling

if !remoteConfigured(peer) { return fmt.Errorf("peer %q not configured", peer) }
if !networkReachable(peerURL) { return ErrPeerUnreachable }

Try / catch

result, err := store.Sync(ctx, peer, "", opts)
if err != nil && strings.HasPrefix(err.Error(), "fetch failed:") {
    return retryWithBackoff(3, func() error {
        _, err = store.Sync(ctx, peer, "", opts); return err
    })
}

Prevention

When it happens

Trigger: store.Sync(ctx, peer, strategy, opts) where s.Fetch(ctx, peer) returns non-nil — unreachable peer, unknown remote, bad credentials, CLI fetch subprocess failure, timeout.

Common situations: Peer server offline or DNS failure; expired credentials; remote renamed; intermittent VPN/firewall blocking the peer URL during scheduled syncs.

Related errors


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