nats-io/nats-server · error
missing 'cert_file' in TLS configuration
Error message
missing 'cert_file' in TLS configuration
What it means
GenTLSConfig emits this when a TLS configuration needs a certificate but tc.CertFile is empty — the switch that validates cert_file/cert_store combinations found no cert_file supplied where one is required (e.g. next to a configured key_file). It fires before any TLS handshake, purely from inspecting the config struct, so the fix is always in the configuration file.
Source
Thrown at server/opts.go:5837
// 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
}
case tc.Certificates != nil:
// Multiple certificate support.View on GitHub (pinned to 3a66a489d2)
Solutions
- Add cert_file pointing to the PEM certificate chain
- Ensure the value is non-empty after any env-var expansion
- If intending a cert store, remove key_file and configure cert_store instead
Example fix
// before
tls { key_file: "/certs/server.key" }
// after
tls {
cert_file: "/certs/server.pem"
key_file: "/certs/server.key"
} Defensive patterns
Strategy: validation
Validate before calling
if cfg.TLS.KeyFile != "" && cfg.TLS.CertFile == "" {
return fmt.Errorf("key_file set but cert_file missing")
} Try / catch
if err := validateTLSPairs(cfg.TLS); err != nil { log.Fatalf("tls config: %v", err) } Prevention
- Set cert_file and key_file as a unit
- Check env-var expansions don't blank out cert_file
- Run 'nats-server -t' config check in CI
When it happens
Trigger: TLS block specifying key_file without cert_file (tc.CertFile == "" && tc.KeyFile != ""), typically in nats-server config 'tls' sections.
Common situations: Config template placeholders left unfilled; cert path typo causing empty resolution elsewhere; partial migration from another server's config format.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- missing 'key_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/73b7bd4ffc16ee81.
Report an issue: GitHub.