caddyserver/caddy · error
private key does not match issuer public key
Error message
private key does not match issuer public key
What it means
meta.json loaded but json.Unmarshal into echConfigMeta failed — the metadata is present but not valid JSON of the expected shape. Caddy's policy is to reset the whole config folder (it cannot reliably maintain a config without metadata), and that cleanup delete failed as well.
Source
Thrown at modules/caddypki/crypto.go:135
return chain, key, nil
default:
return nil, nil, fmt.Errorf("unsupported format: %s", kp.Format)
}
}
// verifyKeysMatch verifies that the public key in the [x509.Certificate] matches
// the public key of the [crypto.Signer].
func verifyKeysMatch(crt *x509.Certificate, signer crypto.Signer) error {
switch pub := crt.PublicKey.(type) {
case *rsa.PublicKey:
pk, ok := signer.Public().(*rsa.PublicKey)
if !ok {
return fmt.Errorf("private key type %T does not match issuer public key type %T", signer.Public(), pub)
}
if !pub.Equal(pk) {
return errors.New("private key does not match issuer public key")
}
case *ecdsa.PublicKey:
pk, ok := signer.Public().(*ecdsa.PublicKey)
if !ok {
return fmt.Errorf("private key type %T does not match issuer public key type %T", signer.Public(), pub)
}
if !pub.Equal(pk) {
return errors.New("private key does not match issuer public key")
}
case ed25519.PublicKey:
pk, ok := signer.Public().(ed25519.PublicKey)
if !ok {
return fmt.Errorf("private key type %T does not match issuer public key type %T", signer.Public(), pub)
}
if !pub.Equal(pk) {
return errors.New("private key does not match issuer public key")
}
default:View on GitHub (pinned to 50e54ee279)
Solutions
- Restore writable storage so the cleanup can proceed.
- Manually delete the affected ech/configs/<id> folder (or the whole ech/configs tree if several configs are affected) and restart Caddy to regenerate.
- Verify storage health (fsync/atomicity) if truncation recurs; prefer the default file storage or a backend with atomic puts.
- Avoid hand-editing files under Caddy's storage.
Example fix
# before: truncated metadata blocks cleanup on read-only storage # after: remount writable, then reset the folder mount -o remount,rw /var/lib/caddy rm -rf /var/lib/caddy/ech/configs/42 systemctl restart caddy
Defensive patterns
Strategy: fallback
Try / catch
On JSON-decode failure, Caddy's fallback is folder reset; it only errors when that reset fails — restore storage writability, remove the named ech/configs/<id> folder (or the whole tree), restart.
Prevention
- Use storage with atomic puts (temp file + rename) so meta.json is never truncated.
- Gracefully stop Caddy (SIGTERM) so metadata writes complete.
- After crashes, run a startup validation pass; reset ech state if decode errors recur.
When it happens
Trigger: json.Unmarshal of non-empty metaBytes errors (truncated JSON from an interrupted write, manual edits, schema change across versions) AND storage.Delete of the config folder errors (read-only/outage).
Common situations: Crash during a metadata Store leaving a truncated meta.json; storage backends without atomic writes; mixed-version clusters where the metadata schema evolved; combined with a storage backend that cannot delete.
Related errors
- ErrInvalidSplitPath
- protocol argument was not a string
- %s is invalid policy
- rfc9112 forbids empty Host
- Buggy browser is sending null Origin header.
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/b0fb178eae5a5fab.
Report an issue: GitHub.