gastownhall/beads · error

failed to encrypt password: %w

Error message

failed to encrypt password: %w

What it means

After ensuring the credential key exists, addFederationPeer encrypts the peer's password with AES-GCM via encryptPassword; this wraps any failure from that encryption. Encryption itself only fails if the in-memory key is missing (should not happen after ensureCredentialKey) or the crypto primitives/nonce generation fail.

Source

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

	})
}

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)
		VALUES (?, ?, ?, ?, ?)
		ON DUPLICATE KEY UPDATE
			remote_url = VALUES(remote_url),
			username = VALUES(username),
			password_encrypted = VALUES(password_encrypted),
			sovereignty = VALUES(sovereignty),
			updated_at = CURRENT_TIMESTAMP
	`, peer.Name, peer.RemoteURL, peer.Username, encryptedPwd, peer.Sovereignty)

	if err != nil {
		return fmt.Errorf("failed to add federation peer: %w", err)
	}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Retry the operation; transient crypto/rand failures usually indicate entropy starvation — fix the host entropy source (e.g. ensure /dev/urandom availability in the container).
  2. Verify the key file is exactly 32 bytes; a corrupt key file means re-initialization is needed (re-add peer credentials afterwards).
  3. Avoid constructing DoltStore manually in tests; use the standard constructor and call ensureCredentialKey before encryption.
Defensive patterns

Strategy: retry

Try / catch

err := store.AddFederationPeer(ctx, peer)
if err != nil && strings.Contains(err.Error(), "failed to encrypt password") {
    // transient crypto/rand failure — retry once after backoff
    time.Sleep(100 * time.Millisecond)
    err = store.AddFederationPeer(ctx, peer)
}

Prevention

When it happens

Trigger: Calling AddFederationPeer with a non-empty peer.Password when encryptWithKey fails — AES cipher/GCM construction error or crypto/rand nonce read failure — or when the key was concurrently reset to nil between ensureCredentialKey and encryptPassword.

Common situations: System entropy exhaustion (crypto/rand read failure in constrained containers); key length corruption (key file truncated to non-32 bytes bypassing the 32-byte check upstream); race conditions on a manually constructed store.

Related errors


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