nats-io/nats-server · error
missing 'key_file' in TLS configuration
Error message
missing 'key_file' in TLS configuration
What it means
During TLS config building (parseTLS/GenericTLSConfig), if cert_file is set but key_file is empty, the server returns this error. A TLS certificate without its matching private key cannot form a usable key pair, so the server rejects the configuration.
Source
Thrown at server/opts.go:5835
}
// GenTLSConfig loads TLS related configuration parameters.
func GenTLSConfig(tc *TLSConfigOpts) (*tls.Config, error) {
// Create the tls.Config from our options before including the certs.
// It will determine the cipher suites that we prefer.
// FIXME(dlc) change if ARM based.
config := tls.Config{
MinVersion: tls.VersionTLS12,
CipherSuites: tc.Ciphers,
CurvePreferences: tc.CurvePreferences,
InsecureSkipVerify: tc.Insecure,
}
switch {
case tc.CertFile != _EMPTY_ && tc.CertStore != certstore.STOREEMPTY:
return nil, certstore.ErrConflictCertFileAndStore
case tc.CertFile != _EMPTY_ && tc.KeyFile == _EMPTY_:
return nil, fmt.Errorf("missing 'key_file' in TLS configuration")
case tc.CertFile == _EMPTY_ && tc.KeyFile != _EMPTY_:
return nil, fmt.Errorf("missing 'cert_file' in TLS configuration")
case tc.CertFile != _EMPTY_ && tc.KeyFile != _EMPTY_:
// Now load in cert and private key
cert, err := tls.LoadX509KeyPair(tc.CertFile, tc.KeyFile)
if err != nil {
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
}View on GitHub (pinned to 3a66a489d2)
Solutions
- Add key_file pointing to the PEM private key alongside cert_file
- If using a cert store instead, remove cert_file and set cert_store
- Verify both paths exist and are readable by the server process
Example fix
// before
https: 8443
tls { cert_file: "/certs/server.pem" }
// after
tls {
cert_file: "/certs/server.pem"
key_file: "/certs/server.key"
} Defensive patterns
Strategy: validation
Validate before calling
if cfg.TLS.CertFile != "" && cfg.TLS.KeyFile == "" {
return fmt.Errorf("cert_file set but key_file missing")
} Try / catch
if err := validateTLSPairs(cfg.TLS); err != nil { log.Fatalf("tls config: %v", err) } Prevention
- Always set cert_file and key_file together in config templates
- Use shared TLS config snippets to keep pairs consistent
- Verify files exist before server start
When it happens
Trigger: TLS block specifying cert_file but omitting key_file, e.g. tc.CertFile != "" && tc.KeyFile == "" in server/opts.go:5835.
Common situations: Incomplete TLS sections in nats-server config; keys stored elsewhere (e.g. hardware/keystore) with only the cert path given; copy-paste dropping the key line.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- missing 'cert_file' in TLS configuration
- leafnode: %v
- unrecognized cipher %s
- unrecognized curve preference %s
- 'min_version' wrong type: %v
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/aba4f2ece04a1484.
Report an issue: GitHub.