caddyserver/caddy · error
marshaling ECH private key: %v
Error message
marshaling ECH private key: %v
What it means
When Caddy creates a new ECH config, it generates an X25519 HPKE key pair and serializes the private half with MarshalBinary before persisting it to storage under ech/configs/<id>/key.bin. For a freshly generated, in-memory X25519 key this call is effectively infallible in the crypto/ecdh-backed hpke library; the check is purely defensive. If it ever fires, it signals an internal invariant break or a library regression, not a user config problem.
Source
Thrown at modules/caddytls/ech.go:665
AEADID: hpke.AEAD_AES128GCM,
},
{
KDFID: hpke.KDF_HKDF_SHA256,
AEADID: hpke.AEAD_AES256GCM,
},
{
KDFID: hpke.KDF_HKDF_SHA256,
AEADID: hpke.AEAD_ChaCha20Poly1305,
},
},
}
meta := echConfigMeta{
Created: time.Now(),
}
privKeyBytes, err := privateKey.MarshalBinary()
if err != nil {
return echConfig{}, fmt.Errorf("marshaling ECH private key: %v", err)
}
echConfigBytes, err := echCfg.MarshalBinary()
if err != nil {
return echConfig{}, fmt.Errorf("marshaling ECH config: %v", err)
}
metaBytes, err := json.Marshal(meta)
if err != nil {
return echConfig{}, fmt.Errorf("marshaling ECH config metadata: %v", err)
}
parentKey := path.Join(echConfigsKey, strconv.Itoa(int(configID)))
keyKey := path.Join(parentKey, "key.bin")
configKey := path.Join(parentKey, "config.bin")
metaKey := path.Join(parentKey, "meta.json")
if err := ctx.Storage().Store(ctx, keyKey, privKeyBytes); err != nil {
return echConfig{}, fmt.Errorf("storing ECH private key: %v", err)
}View on GitHub (pinned to 50e54ee279)
Solutions
- Treat as an internal error: report it upstream to Caddy with the Go and Caddy versions.
- Retry config load/start once to rule out a transient environment issue.
- Pin/rollback the Go toolchain or caddy version if the error appeared right after an upgrade.
Defensive patterns
Strategy: try-catch
Try / catch
if err != nil && strings.Contains(err.Error(), "marshaling ECH private key") {
// internal invariant break: report, do not retry — same result guaranteed
return fmt.Errorf("internal ECH key error, please report upstream: %w", err)
} Prevention
- Pin known-good Caddy/Go versions in deployment images.
- Report occurrences upstream with version info rather than working around.
When it happens
Trigger: Only reachable inside the internal routine that mints a new ECH config (privateKey just returned by hpke KEM_X25519_HKDF_SHA256.Scheme().GenerateKeyPair()). No user input influences it;MarshalBinary on a generated key does not fail in practice.
Common situations: Essentially never seen in the wild. Could appear after a Go or hpke dependency upgrade that changed key serialization semantics, or memory corruption.
Related errors
- invalid KEM ID: %d
- parsing public_key: %w
- invalid KDF ID: %d
- invalid AEAD ID: %d
- recombining SNI matchers: %v
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/498bf20c88ec60f2.
Report an issue: GitHub.