{"record":{"id":"73b7bd4ffc16ee81","repo":"nats-io/nats-server","slug":"missing-cert-file-in-tls-configuration","errorCode":null,"errorMessage":"missing 'cert_file' in TLS configuration","messagePattern":"missing 'cert_file' in TLS configuration","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/opts.go","lineNumber":5837,"sourceCode":"// GenTLSConfig loads TLS related configuration parameters.\nfunc GenTLSConfig(tc *TLSConfigOpts) (*tls.Config, error) {\n\t// Create the tls.Config from our options before including the certs.\n\t// It will determine the cipher suites that we prefer.\n\t// FIXME(dlc) change if ARM based.\n\tconfig := tls.Config{\n\t\tMinVersion:         tls.VersionTLS12,\n\t\tCipherSuites:       tc.Ciphers,\n\t\tCurvePreferences:   tc.CurvePreferences,\n\t\tInsecureSkipVerify: tc.Insecure,\n\t}\n\n\tswitch {\n\tcase tc.CertFile != _EMPTY_ && tc.CertStore != certstore.STOREEMPTY:\n\t\treturn nil, certstore.ErrConflictCertFileAndStore\n\tcase tc.CertFile != _EMPTY_ && tc.KeyFile == _EMPTY_:\n\t\treturn nil, fmt.Errorf(\"missing 'key_file' in TLS configuration\")\n\tcase tc.CertFile == _EMPTY_ && tc.KeyFile != _EMPTY_:\n\t\treturn nil, fmt.Errorf(\"missing 'cert_file' in TLS configuration\")\n\tcase tc.CertFile != _EMPTY_ && tc.KeyFile != _EMPTY_:\n\t\t// Now load in cert and private key\n\t\tcert, err := tls.LoadX509KeyPair(tc.CertFile, tc.KeyFile)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error parsing X509 certificate/key pair: %v\", err)\n\t\t}\n\t\tcert.Leaf, err = x509.ParseCertificate(cert.Certificate[0])\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error parsing certificate: %v\", err)\n\t\t}\n\t\tconfig.Certificates = []tls.Certificate{cert}\n\tcase tc.CertStore != certstore.STOREEMPTY:\n\t\terr := certstore.TLSConfig(tc.CertStore, tc.CertMatchBy, tc.CertMatch, tc.CaCertsMatch, tc.CertMatchSkipInvalid, &config)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\tcase tc.Certificates != nil:\n\t\t// Multiple certificate support.","sourceCodeStart":5819,"sourceCodeEnd":5855,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/opts.go#L5819-L5855","documentation":"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.","triggerScenarios":"TLS block specifying key_file without cert_file (tc.CertFile == \"\" && tc.KeyFile != \"\"), typically in nats-server config 'tls' sections.","commonSituations":"Config template placeholders left unfilled; cert path typo causing empty resolution elsewhere; partial migration from another server's config format.","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"],"exampleFix":"// before\ntls { key_file: \"/certs/server.key\" }\n// after\ntls {\n  cert_file: \"/certs/server.pem\"\n  key_file: \"/certs/server.key\"\n}","handlingStrategy":"validation","validationCode":"if cfg.TLS.KeyFile != \"\" && cfg.TLS.CertFile == \"\" {\n  return fmt.Errorf(\"key_file set but cert_file missing\")\n}","typeGuard":null,"tryCatchPattern":"if err := validateTLSPairs(cfg.TLS); err != nil { log.Fatalf(\"tls config: %v\", err) }","preventionTips":["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"],"tags":["tls","config-validation","missing-file"],"backgroundTag":"tls-certificate-file-missing","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}