micro/go-micro · error

decryption failed (is the key set correctly?)

Error message

decryption failed (is the key set correctly?)

What it means

NaCl secretbox.Open failed to authenticate the ciphertext with the configured symmetric key. Secretbox verifies a MAC before decrypting, so this error means the data was not encrypted with the same 32-byte key that Init loaded, or the data is corrupted.

Source

Thrown at config/secrets/secretbox/secretbox.go:70

func (s *secretBox) Encrypt(in []byte, opts ...secrets.EncryptOption) ([]byte, error) {
	// no opts are expected, so they are ignored

	// there must be a unique nonce for each message
	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 secretbox.Seal(nonce[:], in, &nonce, &s.secretKey), nil
}

func (s *secretBox) Decrypt(in []byte, opts ...secrets.DecryptOption) ([]byte, error) {
	// no options are expected, so they are ignored

	var decryptNonce [24]byte
	copy(decryptNonce[:], in[:24])
	decrypted, ok := secretbox.Open(nil, in[24:], &decryptNonce, &s.secretKey)
	if !ok {
		return []byte{}, errors.New("decryption failed (is the key set correctly?)")
	}
	return decrypted, nil
}

View on GitHub (pinned to 24529f1404)

Solutions

  1. Ensure the same 32-byte key used by Init at encryption time is configured at decryption time; compare keys byte-for-byte across environments.
  2. Keep the payload intact: the first 24 bytes are the nonce and must be included; decode/encode with a stable, lossless encoding (base64) end-to-end.
  3. If keys rotated, keep the old key available to decrypt legacy records and migrate them to the new key.
  4. Verify Init succeeded with no error and that the key length check (32 bytes) passed.

Example fix

// before
decrypted, err := sb.Decrypt(storedString) // may have lost bytes
// after
raw, err := base64.StdEncoding.DecodeString(storedString)
if err != nil { return err }
decrypted, err := sb.Decrypt(raw) // same key as used to encrypt
Defensive patterns

Strategy: try-catch

Validate before calling

if len(ciphertext) <= 24 {
    return errors.New("payload too short: missing nonce")
}

Try / catch

decrypted, err := sb.Decrypt(payload)
if err != nil {
    if strings.Contains(err.Error(), "is the key set correctly") {
        return fmt.Errorf("secretbox key mismatch or corrupt payload: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling secretBox.Decrypt on data encrypted with a different key; the ciphertext's first 24 bytes (nonce) were stripped or altered; the payload was truncated or double-decoded before Decrypt.

Common situations: Two environments (staging vs production) with different SECRETBOX keys but shared stored ciphertext; key rotation where old records still use the previous key; storing ciphertext through a lossy transformation (e.g. writing bytes as a string with encoding changes).

Related errors


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