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
- Pass secrets.WithRecipientPublicKey(peerKey) to Encrypt with the peer's raw 32-byte curve25519 public key.
- Verify the key length before calling: len(key) == 32; decode base64/hex fully and check for truncation.
- 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.
- 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
- Always pass secrets.WithRecipientPublicKey with the peer's raw 32-byte key to Encrypt.
- Decode keys from base64/hex once at startup and assert length 32.
- Don't confuse Init-time keypair options with Encrypt's per-call recipient option.
- Keep a key-encoding test that round-trips Encrypt/Decrypt between two peers.
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
- sender's public key bust be provided
- incoming message couldn't be verified / decrypted
- no secret key is defined
- agent: StreamAsk unsupported by implementation
- agent: ResumeStreamAsk unsupported by implementation
AI-assisted analysis of micro/go-micro@24529f1404 (2026-09-01).
Data as JSON: /api/errors/e9fd1190a3d370c5.
Report an issue: GitHub.