micro/go-micro · error

recepient's public key must be provided

Error message

recepient's public key must be provided

What it means

The nacl/box secrets provider performs asymmetric encryption using the sender's private key (set at Init) and a recipient public key that must be supplied per-call via secrets.EncryptOption (WithRecipientPublicKey). Encrypt requires that key to be exactly 32 bytes (keyLength); if it is missing, empty, or the wrong length, it returns "recepient's public key must be provided" and no encryption happens.

Source

Thrown at config/secrets/box/box.go:59

// Options returns options.
func (b *box) Options() secrets.Options {
	return b.options
}

// String returns nacl-box.
func (*box) String() string {
	return "nacl-box"
}

// Encrypt encrypts a message with the sender's private key and the receipient's public key.
func (b *box) Encrypt(in []byte, opts ...secrets.EncryptOption) ([]byte, error) {
	var options secrets.EncryptOptions
	for _, o := range opts {
		o(&options)
	}
	if len(options.RecipientPublicKey) != keyLength {
		return []byte{}, errors.New("recepient's public key must be provided")
	}
	var recipientPublicKey [keyLength]byte
	copy(recipientPublicKey[:], options.RecipientPublicKey)
	var nonce [24]byte
	if _, err := rand.Reader.Read(nonce[:]); err != nil {
		return []byte{}, errors.Wrap(err, "couldn't obtain a random nonce from crypto/rand")
	}
	return naclbox.Seal(nonce[:], in, &nonce, &recipientPublicKey, &b.privateKey), nil
}

// Decrypt Decrypts a message with the receiver's private key and the sender's public key.
func (b *box) Decrypt(in []byte, opts ...secrets.DecryptOption) ([]byte, error) {
	var options secrets.DecryptOptions
	for _, o := range opts {
		o(&options)
	}
	if len(options.SenderPublicKey) != keyLength {
		return []byte{}, errors.New("sender's public key bust be provided")

View on GitHub (pinned to 24529f1404)

Solutions

  1. Pass secrets.WithRecipientPublicKey(peerKey) to Encrypt with the peer's raw 32-byte curve25519 public key.
  2. Verify the key length before calling: len(key) == 32; decode base64/hex fully and check for truncation.
  3. Make sure you're not confusing the Init-time keypair options with the per-call EncryptOption — Init's keys alone are not enough for Encrypt.
  4. Share keys in a fixed encoding (e.g. base64) and decode with strict length validation at load time.

Example fix

// before
ciphertext, err := boxSecrets.Encrypt(data) // missing recipient key
// after
if len(peerKey) != 32 {
    return nil, fmt.Errorf("recipient key must be 32 bytes, got %d", len(peerKey))
}
ciphertext, err := boxSecrets.Encrypt(data, secrets.WithRecipientPublicKey(peerKey))
Defensive patterns

Strategy: validation

Validate before calling

if len(peerPublicKey) != 32 {
    return nil, fmt.Errorf("recipient public key must be 32 bytes, got %d", len(peerPublicKey))
}
ciphertext, err := secrets.Encrypt(data, secrets.WithRecipientPublicKey(peerPublicKey))

Type guard

func validRecipientKey(k []byte) bool { return len(k) == 32 }

Try / catch

ct, err := s.Encrypt(data, secrets.WithRecipientPublicKey(peerKey))
if err != nil {
    if strings.Contains(err.Error(), "public key must be provided") {
        return nil, fmt.Errorf("encryption misconfigured: recipient key missing or wrong size")
    }
    return nil, err
}

Prevention

When it happens

Trigger: Calling secrets.Encrypt(data) without any EncryptOption, or with secrets.WithRecipientPublicKey(key) where len(key) != 32 — e.g. an empty slice, a base64 string's raw bytes of different length, or a truncated/hex-decoded-incorrectly key.

Common situations: Forgetting the recipient option in a code path that only configured the box's own keypair at Init; storing keys as hex/base64 strings and passing the wrong representation (wrong byte length); rotating keys and passing a peer's old or mis-copied key; mixing up Encrypt's recipient key with Init's public key.

Related errors


AI-assisted analysis of micro/go-micro@24529f1404 (2026-09-01). Data as JSON: /api/errors/e9fd1190a3d370c5. Report an issue: GitHub.