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

  1. Check the peer exists: GetFederationPeer with the exact name; add it via AddFederationPeer if missing.
  2. Fix the name typo — names are case-sensitive and validated (alphanumeric/hyphen/underscore).
  3. If the inner error is a decrypt/key error, restore .beads/.beads-credential-key or re-add the peer's password.
  4. 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

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


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