gastownhall/beads · error

invalid peer name: %w

Error message

invalid peer name: %w

What it means

addFederationPeer validates the peer name before storing credentials; this wraps any validatePeerName failure. A valid peer name must be non-empty, at most 64 characters, start with a letter, and contain only alphanumerics, hyphens, and underscores (regex ^[a-zA-Z][a-zA-Z0-9_-]*$). The name is later used as a Dolt remote name, so unsafe characters are rejected up front.

Source

Thrown at internal/storage/dolt/credentials.go:275

	s.mu.RUnlock()
	if key == nil {
		return "", fmt.Errorf("credential encryption key not initialized")
	}
	return decryptWithKey(encrypted, key)
}

// AddFederationPeer adds or updates a federation peer with credentials.
// This stores credentials in the database and also adds the Dolt remote.
func (s *DoltStore) AddFederationPeer(ctx context.Context, peer *storage.FederationPeer) error {
	return s.withCircuitWrite(ctx, func(ctx context.Context) error {
		return s.addFederationPeer(ctx, peer)
	})
}

func (s *DoltStore) addFederationPeer(ctx context.Context, peer *storage.FederationPeer) error {
	// Validate peer name
	if err := validatePeerName(peer.Name); err != nil {
		return fmt.Errorf("invalid peer name: %w", err)
	}

	// Encrypt password before storing
	var encryptedPwd []byte
	var err error
	if peer.Password != "" {
		if err := s.ensureCredentialKey(ctx); err != nil {
			return fmt.Errorf("failed to initialize credential key: %w", err)
		}
		encryptedPwd, err = s.encryptPassword(peer.Password)
		if err != nil {
			return fmt.Errorf("failed to encrypt password: %w", err)
		}
	}

	// Upsert the peer credentials
	_, err = s.execContext(ctx, `
		INSERT INTO federation_peers (name, remote_url, username, password_encrypted, sovereignty)

View on GitHub (pinned to 71377f2769)

Solutions

  1. Fix the peer name to match ^[a-zA-Z][a-zA-Z0-9_-]*$ (max 64 chars, starts with a letter).
  2. Sanitize derived names: replace '.', '/', ':' etc. with '-' and strip leading non-letters before calling AddFederationPeer.
  3. Call validatePeerName-equivalent checks (regex) in your own config loading to fail early with a clear message.

Example fix

// before
peer.Name = "team.example.com"
_ = store.AddFederationPeer(ctx, peer)
// after
peer.Name = "team-example-com"
_ = store.AddFederationPeer(ctx, peer)
Defensive patterns

Strategy: validation

Validate before calling

var peerNameRe = regexp.MustCompile(`^[a-zA-Z][a-zA-Z0-9_-]*$`)
if peer.Name == "" || len(peer.Name) > 64 || !peerNameRe.MatchString(peer.Name) {
    return fmt.Errorf("peer name %q is invalid", peer.Name)
}

Try / catch

if err := store.AddFederationPeer(ctx, peer); err != nil && strings.HasPrefix(err.Error(), "invalid peer name") {
    return fmt.Errorf("fix peer name %q: %w", peer.Name, err)
}

Prevention

When it happens

Trigger: Calling AddFederationPeer with a peer.Name that is empty, longer than 64 chars, starts with a digit/underscore/hyphen, or contains spaces, dots, slashes, or other special characters.

Common situations: Deriving peer names from hostnames or URLs containing dots/slashes (e.g. "team.example.com", "org/repo"); user-supplied names from config files or CLI flags without pre-validation; accidentally passing an empty struct.

Related errors


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