gastownhall/beads · error
fetch failed: %w
Error message
fetch failed: %w
What it means
Sync fetches the peer remote before merging. Any failure from store.Fetch(ctx, peer) — network unreachable, unknown remote, bad refspec, or Dolt fetch internals — is wrapped as 'fetch failed'. result.Fetched stays false, so the sync aborted before any merge work.
Source
Thrown at internal/storage/embeddeddolt/federation.go:311
result := &storage.SyncResult{
Peer: peer,
StartTime: time.Now(),
}
// GH#2474 / bd-578h9.2: commit pending changes before the merge, matching
// embedded Pull/PullRemote/PullFrom and server-mode Sync. Embedded Commit is
// DOLT_COMMIT('-Am'), so it stages config — where kv.memory.* memories live —
// and a leftover dirty working set (e.g. a `bd remember` write) would
// otherwise make DOLT_MERGE refuse to start ("cannot merge with uncommitted
// changes"). CommitPending is a no-op when the working set is already clean.
if _, err := s.CommitPending(ctx, "beads"); err != nil {
result.Error = fmt.Errorf("commit pending before sync: %w", err)
return result, result.Error
}
// Step 1: Fetch
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 commit before merge for change detection
beforeCommit, _ := s.GetCurrentCommit(ctx)
// 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 len(conflicts) > 0 {
result.Conflicts = conflictsView on GitHub (pinned to 71377f2769)
Solutions
- Verify the peer remote is registered and reachable (`dolt remote -v`, ping the host).
- Check/refresh credentials for the remote transport (SSH keys, tokens).
- Retry sync once connectivity is restored — fetch is safe to retry.
- Correct the peer name/URL configuration and re-run sync.
Example fix
// before: peer offline -> fetch failed
result, err := store.Sync(ctx, "laptop")
// after: probe reachability first
if err := checkPeerReachable("laptop"); err != nil {
return fmt.Errorf("defer sync: peer unreachable: %w", err)
}
result, err = store.Sync(ctx, "laptop") Defensive patterns
Strategy: retry
Validate before calling
// probe the peer before syncing
func peerReachable(peer string) error {
conn, err := net.DialTimeout("tcp", peerHost(peer), 5*time.Second)
if err != nil { return err }
return conn.Close()
} Try / catch
result, err := store.Sync(ctx, peer)
if err != nil && strings.Contains(err.Error(), "fetch failed") {
// fetch is idempotent: back off and retry
time.Sleep(backoff)
result, err = store.Sync(ctx, peer)
} Prevention
- Register and verify peer remotes before scheduling syncs.
- Refresh SSH keys/tokens before expiry.
- Health-check peers before federation jobs.
- Use bounded retries with backoff for transient network faults.
When it happens
Trigger: store.Sync(ctx, peer) where s.Fetch(ctx, peer) errors: the peer remote is not configured, the peer is offline/unreachable, SSH/HTTPS credentials are missing or expired, or the peer repo path is wrong.
Common situations: Peer machine is down during federation sync; remote URL typo in peer configuration; expired credentials/token; firewall blocking the transport; peer branch was force-removed.
Related errors
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/1951c63340888b7e.
Report an issue: GitHub.