golang/go · error

unsupported KEM

Error message

unsupported KEM

What it means

NewKEM maps a numeric KEM ID (IANA HPKE registry) to an implementation. Only specific IDs are recognised: 0x0010-0x0012 (DHKEM P-256/P-384/P-521), 0x0020 (DHKEM X25519), 0x0041/0x0042 (ML-KEM-768/1024), 0x647a (MLKEM768-X25519), 0x0050 (MLKEM768-P256), 0x0051 (MLKEM1024-P384). Any other value falls through to the error.

Source

Thrown at src/crypto/hpke/kem.go:67

		return DHKEM(ecdh.P256()), nil
	case 0x0011: // DHKEM(P-384, HKDF-SHA384)
		return DHKEM(ecdh.P384()), nil
	case 0x0012: // DHKEM(P-521, HKDF-SHA512)
		return DHKEM(ecdh.P521()), nil
	case 0x0020: // DHKEM(X25519, HKDF-SHA256)
		return DHKEM(ecdh.X25519()), nil
	case 0x0041: // ML-KEM-768
		return MLKEM768(), nil
	case 0x0042: // ML-KEM-1024
		return MLKEM1024(), nil
	case 0x647a: // MLKEM768-X25519
		return MLKEM768X25519(), nil
	case 0x0050: // MLKEM768-P256
		return MLKEM768P256(), nil
	case 0x0051: // MLKEM1024-P384
		return MLKEM1024P384(), nil
	default:
		return nil, errors.New("unsupported KEM")
	}
}

// A PublicKey is an instantiation of a KEM (one of the three components of an
// HPKE ciphersuite) with an encapsulation key (i.e. the public key).
//
// A PublicKey is usually obtained from a method of the corresponding [KEM] or
// [PrivateKey], such as [KEM.NewPublicKey] or [PrivateKey.PublicKey].
type PublicKey interface {
	// KEM returns the instantiated KEM.
	KEM() KEM

	// Bytes returns the public key as the output of SerializePublicKey.
	Bytes() []byte

	encap() (sharedSecret, enc []byte, err error)
}

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Use a symbolic constructor (DHKEM, MLKEM768, MLKEM768X25519, etc.) instead of a raw numeric ID.
  2. Cross-check the ID against RFC 9180 §36 and the IANA HPKE registry before passing it in.
  3. Verify endianness: KEM IDs in HPKE are big-endian uint16.

Example fix

// before
kem, err := hpke.NewKEM(0x1000) // transposed -> "unsupported KEM"

// after
kem, err := hpke.NewKEM(0x0010) // DHKEM(P-256)
// or, preferred:
kem := hpke.DHKEM(ecdh.P256())
Defensive patterns

Strategy: validation

Validate before calling

// Allowlist of supported KEM IDs for this build.
var supportedKEMs = map[uint16]string{
    0x0010: "DHKEM(P-256)", 0x0011: "DHKEM(P-384)", 0x0012: "DHKEM(P-521)",
    0x0020: "DHKEM(X25519)", 0x0041: "ML-KEM-768", 0x0042: "ML-KEM-1024",
    0x647A: "MLKEM768-X25519", 0x0050: "MLKEM768-P256", 0x0051: "MLKEM1024-P384",
}
func kemFor(id uint16) (hpke.KEM, error) {
    if _, ok := supportedKEMs[id]; !ok {
        return nil, fmt.Errorf("KEM 0x%04x not supported by this build", id)
    }
    return hpke.NewKEM(id)
}

Try / catch

kem, err := hpke.NewKEM(id)
if err != nil {
    if err.Error() == "unsupported KEM" {
        return fmt.Errorf("unknown KEM id 0x%04x; check IANA HPKE registry", id)
    }
    return err
}

Prevention

When it happens

Trigger: Calling hpke.NewKEM(id) with an unregistered, mistyped, or unsupported KEM ID. Also hit by byte-order mistakes (e.g. passing 0x1000 instead of 0x0010).

Common situations: Hardcoding a KEM ID from memory and transposing digits; reading an ID off the wire that the local build doesn't support; using a future/draft KEM ID not yet implemented.

Related errors


AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12). Data as JSON: /api/errors/469d29cb5fef8434. Report an issue: GitHub.