AdguardTeam/AdGuardHome · critical
loading tls certificate: %w
Error message
loading tls certificate: %w
What it means
The TLS manager could not parse the configured certificate chain and private key pair into a tls.Certificate via tls.X509KeyPair. The wrapped error is a crypto/tls parse failure: malformed PEM, truncated data, or a key that does not match the certificate.
Source
Thrown at internal/aghtls/defaultmanager.go:477
mgr.logger.ErrorContext(ctx, "setting tls files", slogutil.KeyError, err)
}
mgr.setCertFileTime(ctx)
return restartHTTPS, nil
}
// updateTLSCert loads and updates a TLS certificate for m.tlsConf. If
// m.tlsConf is nil, it will be initialized. extTLSConf must not be nil. m.mu
// must be locked.
func (mgr *DefaultManager) updateTLSCert(extTLSConf *ExtendedTLSConfig) (err error) {
if len(extTLSConf.CertificateChainData) == 0 || len(extTLSConf.PrivateKeyData) == 0 {
return nil
}
cert, err := tls.X509KeyPair(extTLSConf.CertificateChainData, extTLSConf.PrivateKeyData)
if err != nil {
return fmt.Errorf("loading tls certificate: %w", err)
}
slices.Sort(cert.Leaf.DNSNames)
if mgr.tlsConf == nil {
mgr.tlsConf = &tls.Config{
RootCAs: mgr.rootCerts,
CipherSuites: mgr.customCipherIDs,
MinVersion: tls.VersionTLS12,
GetCertificate: mgr.onGetCertificate,
}
}
mgr.tlsCert = &cert
return nil
}
View on GitHub (pinned to b41aefbe51)
Solutions
- Validate the pair externally: openssl x509 -in cert.pem -noout -modulus vs openssl rsa -in key.pem -noout -modulus (or -pubkey comparison for EC)
- Confirm both files are PEM (BEGIN CERTIFICATE / BEGIN PRIVATE KEY headers)
- If caused by atomic cert replacement, ensure the reload reads files after the rename completes rather than during
- Regenerate the certificate/key pair together if they mismatch
Example fix
// before CertificateChainData: derBytes, // wrong encoding PrivateKeyData: pemKey, // after CertificateChainData: pemCert, PrivateKeyData: pemKey,
Defensive patterns
Strategy: validation
Validate before calling
if _, err := tls.X509KeyPair(certPEM, keyPEM); err != nil {
return fmt.Errorf("rejecting bad pair before update: %w", err)
} Try / catch
if err := mgr.SetExtendedTLSConfig(ctx, conf); err != nil {
// keep serving the previous valid certificate; log and retry next reload
log.Error("cert reload failed; keeping previous cert", "err", err)
} Prevention
- Validate PEM data with tls.X509KeyPair before assigning it to the manager
- Read cert files atomically (snapshot both files after rename)
- Alert on renewal pipelines so mismatched pairs are caught early
When it happens
Trigger: updateTLSCert runs on reload or SetExtendedTLSConfig when CertificateChainData/PrivateKeyData are populated but not a valid pair: corrupt PEM blocks, cert signed with a different key, or binary/DER data supplied instead of PEM.
Common situations: Certificates updated on disk mid-read (torn read of a partially written file); mixing up fullchain.pem and privkey.pem; supplying DER instead of PEM; key regenerated after CSR while old cert retained.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- parsing tls certificate: %w
- parsing certificate at index %d: %w
- certificate does not verify: %w
- certificate-key pair: %w
- unknown cipher %q
AI-assisted analysis of AdguardTeam/AdGuardHome@b41aefbe51 (2026-08-27).
Data as JSON: /api/errors/7e5204865f5a2e2e.
Report an issue: GitHub.