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 = conflictsView on GitHub (pinned to 71377f2769)
Solutions
- Read the wrapped cause (%w) to distinguish network vs auth vs unknown-remote
- Verify peer connectivity and remote config (`dolt remote -v`, `dolt ls-remote <peer>`)
- Refresh credentials for the peer and retry the sync
- Add retry/backoff around Sync for transient outages
- 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
- Health-check the peer before each scheduled sync
- Use retry/backoff for transient network conditions
- Keep remote names/URLs stable across re-clones; migrate rather than rename
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.