caddyserver/caddy · error
invalid KDF ID: %d
Error message
invalid KDF ID: %d
What it means
ECH config decoding iterates the length-prefixed list of (KDF, AEAD) cipher suite pairs (each 4 bytes). Each KDF ID is validated with hpke.KDF(id).IsValid(); Caddy writes KDF_HKDF_SHA256 (0x0001) and KDF_HKDF_SHA512 may exist depending on the linked hpke version. An unrecognized numeric KDF ID aborts parsing with the offending value.
Source
Thrown at modules/caddytls/ech.go:1013
if !echCfg.KEMID.IsValid() {
return fmt.Errorf("invalid KEM ID: %d", echCfg.KEMID)
}
var err error
if echCfg.PublicKey, err = echCfg.KEMID.Scheme().UnmarshalBinaryPublicKey(pk); err != nil {
return fmt.Errorf("parsing public_key: %w", err)
}
echCfg.CipherSuites = echCfg.CipherSuites[:0]
for !t.Empty() {
var hpkeKDF, hpkeAEAD uint16
if !t.ReadUint16(&hpkeKDF) || !t.ReadUint16(&hpkeAEAD) {
// we have already checked that the length is divisible by 4
panic("this must not happen")
}
if !hpke.KDF(hpkeKDF).IsValid() {
return fmt.Errorf("invalid KDF ID: %d", hpkeKDF)
}
if !hpke.AEAD(hpkeAEAD).IsValid() {
return fmt.Errorf("invalid AEAD ID: %d", hpkeAEAD)
}
echCfg.CipherSuites = append(echCfg.CipherSuites, hpkeSymmetricCipherSuite{
KDFID: hpke.KDF(hpkeKDF),
AEADID: hpke.AEAD(hpkeAEAD),
})
}
var rawPublicName []byte
if !content.ReadUint8(&echCfg.MaxNameLength) ||
!content.ReadUint8LengthPrefixed(&t) ||
!t.ReadBytes(&rawPublicName, len(t)) ||
!content.ReadUint16LengthPrefixed(&t) ||
!t.ReadBytes(&echCfg.RawExtensions, len(t)) ||
!content.Empty() {
return errInvalidLenView on GitHub (pinned to 50e54ee279)
Solutions
- Remove the malformed stored ECH configs (ech/configs/*) to regenerate with the standard SHA-256 KDF.
- Regenerate external configs restricting suites to HKDF-SHA256-based ones.
- Upgrade Caddy so its hpke dependency recognizes the KDF if it's a legitimate newer ID.
Defensive patterns
Strategy: validation
Try / catch
if err != nil && strings.Contains(err.Error(), "invalid KDF ID") {
// prune stored configs; regenerate with standard HKDF-SHA256 suites
} Prevention
- Don't hand-craft ECH config binaries; let Caddy generate them.
- Keep the hpke dependency set consistent across builds.
When it happens
Trigger: UnmarshalBinary over data whose cipher-suite list contains a KDF ID unknown to the linked hpke package — corrupt bytes or an ECH config from an implementation using KDFs Go's hpke doesn't register.
Common situations: Corrupted storage blobs; consuming cross-implementation ECH configs that include HKDF-SHA384 or other KDFs; version skew between Caddy builds with different hpke versions.
Related errors
- invalid KEM ID: %d
- parsing public_key: %w
- invalid AEAD ID: %d
- marshaling ECH private key: %v
- marshaling ECH config: %v
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/038de60bfd6f373f.
Report an issue: GitHub.