nats-io/nats-server · error
error parsing X509 certificate/key pair %d/%d: %v
Error message
error parsing X509 certificate/key pair %d/%d: %v
What it means
In the multi-certificate path (tc.Certificates list), the server loads each pair with tls.LoadX509KeyPair and wraps failures as 'error parsing X509 certificate/key pair %d/%d: %v', identifying which of N pairs failed (1-based index). The wrapped error contains the actual cause.
Source
Thrown at server/opts.go:5860
return nil, fmt.Errorf("error parsing X509 certificate/key pair: %v", err)
}
cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0])
if err != nil {
return nil, fmt.Errorf("error parsing certificate: %v", err)
}
config.Certificates = []tls.Certificate{cert}
case tc.CertStore != certstore.STOREEMPTY:
err := certstore.TLSConfig(tc.CertStore, tc.CertMatchBy, tc.CertMatch, tc.CaCertsMatch, tc.CertMatchSkipInvalid, &config)
if err != nil {
return nil, err
}
case tc.Certificates != nil:
// Multiple certificate support.
config.Certificates = make([]tls.Certificate, len(tc.Certificates))
for i, certPair := range tc.Certificates {
cert, err := tls.LoadX509KeyPair(certPair.CertFile, certPair.KeyFile)
if err != nil {
return nil, fmt.Errorf("error parsing X509 certificate/key pair %d/%d: %v", i+1, len(tc.Certificates), err)
}
cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0])
if err != nil {
return nil, fmt.Errorf("error parsing certificate %d/%d: %v", i+1, len(tc.Certificates), err)
}
config.Certificates[i] = cert
}
}
// Require client certificates as needed
if tc.Verify {
config.ClientAuth = tls.RequireAndVerifyClientCert
}
// Add in CAs if applicable.
if tc.CaFile != _EMPTY_ {
rootPEM, err := os.ReadFile(tc.CaFile)
if err != nil || rootPEM == nil {
return nil, errView on GitHub (pinned to 3a66a489d2)
Solutions
- Fix the failing pair indicated by the first number (i+1) in the message — check file existence, PEM validity, and cert/key matching for that entry
- Validate all pairs offline with tls.LoadX509KeyPair in a small test program before restart
- Remove stale entries from the certificate list
Defensive patterns
Strategy: validation
Validate before calling
for i, p := range cfg.TLS.Certificates {
if _, err := tls.LoadX509KeyPair(p.CertFile, p.KeyFile); err != nil {
return fmt.Errorf("pair %d/%d invalid: %w", i+1, len(cfg.TLS.Certificates), err)
}
} Try / catch
if err := preflightAllPairs(cfg.TLS.Certificates); err != nil {
log.Fatalf("multi-cert config invalid: %v", err)
} Prevention
- Pre-flight load every pair before restart
- When rotating, update all entries atomically
- Delete entries whose files no longer exist
When it happens
Trigger: Providing multiple certificate pairs via the Certificates option where any one pair fails to load — unreadable files, mismatched cert/key, invalid PEM.
Common situations: Rotating certificates where one of several SNI pairs was updated incompletely; duplicated config entries pointing at removed files.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- error parsing X509 certificate/key pair: %v
- error parsing certificate: %v
- error parsing certificate %d/%d: %v
- invalid type name: %+v
- invalid type value: %+v
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/c2dbb0570c7c61d6.
Report an issue: GitHub.