gastownhall/beads · error

failed to fetch from peer %s: %w

Error message

failed to fetch from peer %s: %w

What it means

Wraps a failure of `CALL DOLT_FETCH(?)` (or the CLI fetch path) when fetching refs from a peer remote without merging. Fetch is the first step of every sync, so this error usually blocks synchronization entirely. The wrapped cause distinguishes network failures, unknown remotes, and auth problems.

Source

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

// For git-protocol remotes, uses CLI `dolt fetch` to avoid MySQL connection timeouts.
func (s *DoltStore) Fetch(ctx context.Context, peer string) error {
	if useCLI, err := s.prepareCLIRouteForPeerGitProtocol(ctx, peer); err != nil {
		return err
	} else if useCLI {
		return s.withPeerCredentials(ctx, peer, func(creds *remoteCredentials) error {
			return s.doltCLIFetchFromPeer(ctx, peer, creds)
		})
	}
	return s.withPeerCredentials(ctx, peer, func(creds *remoteCredentials) error {
		// Credential CLI routing: route fetch through CLI subprocess.
		if useCLI, err := s.prepareCLIRouteForPeerCredentials(ctx, peer, creds); err != nil {
			return err
		} else if useCLI {
			return s.doltCLIFetchFromPeer(ctx, peer, creds)
		}
		return withEnvCredentials(creds, func() error {
			if err := s.execWithLongTimeout(ctx, "CALL DOLT_FETCH(?)", peer); err != nil {
				return fmt.Errorf("failed to fetch from peer %s: %w", peer, err)
			}
			return nil
		})
	})
}

// ListRemotes returns configured remote names and URLs.
func (s *DoltStore) ListRemotes(ctx context.Context) ([]storage.RemoteInfo, error) {
	return versioncontrolops.ListRemotes(ctx, s.db)
}

// hasPersistedCLIRemote reports whether a Dolt remote is persisted on disk in
// .dolt/repo_state.json — in the database CLI directory (CLIDir) or the dolt
// server root (Path, per GH#2118). A freshly (auto-)started sql-server can
// report an empty dolt_remotes table at store open even though remotes are
// persisted on disk. The #4259 remote-migrate gate therefore consults this
// directly so a cold-start open cannot miss the remote and migrate the shared
// database in place.

View on GitHub (pinned to 71377f2769)

Solutions

  1. Check network reachability of the peer URL (`dolt ls-remote <remote>` or curl the URL)
  2. Verify the remote name/URL with `dolt remote -v` and re-add if renamed: `dolt remote set-url <name> <url>`
  3. Refresh stored credentials for the peer; confirm env credentials via withEnvCredentials (GITHUB_TOKEN etc.)
  4. If the SQL route times out, force the CLI route (the code prefers it for git-protocol remotes) or increase the long-timeout window
  5. Retry after transient outage — fetch is safe to re-run

Example fix

// before
if err := store.Fetch(ctx, "origin"); err != nil { panic(err) }
// after: retry transient fetch failures
err := store.Fetch(ctx, "origin")
for i := 0; err != nil && i < 3; i++ {
    time.Sleep(time.Duration(1<<i) * time.Second)
    err = store.Fetch(ctx, "origin")
}
Defensive patterns

Strategy: retry

Validate before calling

remotes, _ := store.ListRemotes(ctx)
if !remoteExists(remotes, peer) { return fmt.Errorf("unknown peer %q", peer) }
// plus network probe:
if err := probeRemoteURL(peerURL); err != nil { return err }

Type guard

func isFetchable(peer string) bool { return peer != "" && remoteConfigured(peer) }

Try / catch

if err := store.Fetch(ctx, peer); err != nil {
    if isTransient(err) { // network/timeout
        return retryWithBackoff(3, func() error { return store.Fetch(ctx, peer) })
    }
    return fmt.Errorf("fetch %s: %w", peer, err)
}

Prevention

When it happens

Trigger: Calling Fetch(ctx, peer) or Sync's Step 1 where DOLT_FETCH against the peer's remote errors — unreachable URL, TLS failure, unknown remote name, invalid credentials, or CLI fetch subprocess failure.

Common situations: Offline or firewalled environment; peer git server (GitHub/Forgejo) down or rate-limiting; remote name changed after re-cloning; expired token in stored credentials; MySQL connection timeout on the SQL route (why the CLI route exists).

Related errors


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