gastownhall/beads · error
failed to get peer credentials: %w
Error message
failed to get peer credentials: %w
What it means
withPeerCredentials fetches a federation peer's stored credentials before running a push/pull/fetch callback. This error wraps any failure from GetFederationPeer — most commonly the peer not existing (storage.ErrNotFound 'federation peer <name>'), but also SQL failures and password decryption failures. The library throws it so sync operations fail early with a credential-lookup message instead of attempting an unauthenticated remote operation.
Source
Thrown at internal/storage/dolt/credentials.go:610
// withEnvCredentials executes fn with credentials set as process-wide env vars,
// protected by federationEnvMutex. This is required for SQL-path operations
// (CALL DOLT_PUSH/PULL) where the in-process Dolt server reads credentials
// from the process environment. CLI operations should NOT use this — use
// remoteCredentials.applyToCmd instead for race-free subprocess isolation.
func withEnvCredentials(creds *remoteCredentials, fn func() error) error {
return withRemoteOperationEnv(creds, false, fn)
}
// withPeerCredentials looks up credentials for a federation peer and passes
// them to fn. The callback receives the credentials and is responsible for
// applying them appropriately: CLI operations use creds.applyToCmd for
// subprocess isolation; SQL operations use withEnvCredentials for mutex-protected
// process env access.
func (s *DoltStore) withPeerCredentials(ctx context.Context, peerName string, fn func(creds *remoteCredentials) error) error {
peer, err := s.GetFederationPeer(ctx, peerName)
if err != nil {
return fmt.Errorf("failed to get peer credentials: %w", err)
}
var creds *remoteCredentials
if peer != nil && (peer.Username != "" || peer.Password != "") {
creds = &remoteCredentials{username: peer.Username, password: peer.Password}
}
err = fn(creds)
// Update last sync time on success
if err == nil && peer != nil {
_ = s.updatePeerLastSync(ctx, peerName) // Best effort: peer sync timestamp is advisory
}
return err
}
// FederationPeer is an alias for storage.FederationPeer for convenience.View on GitHub (pinned to 71377f2769)
Solutions
- Check the peer exists: GetFederationPeer with the exact name; add it via AddFederationPeer if missing.
- Fix the name typo — names are case-sensitive and validated (alphanumeric/hyphen/underscore).
- If the inner error is a decrypt/key error, restore .beads/.beads-credential-key or re-add the peer's password.
- If it's a connectivity error, reconnect to the dolt-sql-server and retry.
Example fix
// before
err := store.Push(ctx, ...) // failed to get peer credentials: federation peer alice not found
// after: register the peer first
err = store.AddFederationPeer(ctx, &storage.FederationPeer{Name: "alice", RemoteURL: "https://doltremoteapi.dolthub.com/org/repo", Username: "u", Password: "p"}) Defensive patterns
Strategy: type-guard
Validate before calling
// check peer exists before sync operations
if _, err := store.GetFederationPeer(ctx, peerName); err != nil {
return fmt.Errorf("peer %q not configured; add it via AddFederationPeer", peerName)
} Type guard
func isPeerNotFound(err error) bool {
return errors.Is(err, storage.ErrNotFound) && strings.Contains(err.Error(), "federation peer")
} Try / catch
err := store.Push(ctx, ...)
if isPeerNotFound(err) {
// register the peer then retry
if addErr := store.AddFederationPeer(ctx, &storage.FederationPeer{Name: peerName, RemoteURL: url, Username: u, Password: p}); addErr != nil { return addErr }
err = store.Push(ctx, ...)
} Prevention
- Validate peer names against ListFederationPeers before syncing
- Remove peers and their consuming scripts together
- Store peer names in config rather than hardcoding strings
- Handle storage.ErrNotFound distinctly from transient SQL errors
When it happens
Trigger: Calling pushRefToPeer/pullFromPeer/Fetch with a peer name that has no row in federation_peers (never added via AddFederationPeer or already removed); the underlying SELECT fails (connection down); or the stored password can't be decrypted.
Common situations: Typo in the peer/remote name when syncing; removing a peer but still pushing to it from a script; database connectivity loss; key-file mismatch causing decrypt errors surfaced here.
Related errors
- epic '%s' not found
- issue '%s' not found
- %w: federation peer %s
- failed to decrypt password: %w
- failed to commit pending changes before sync: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/56ae92246aca3a04.
Report an issue: GitHub.