{"record":{"id":"b323906ed1b58cfe","repo":"crowdsecurity/crowdsec","slug":"missing-tls-cert-file","errorCode":null,"errorMessage":"missing TLS cert file","messagePattern":"missing TLS cert file","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/acquisition/modules/appsec/run.go","lineNumber":37,"sourceCode":"\t\"github.com/crowdsecurity/crowdsec/pkg/pipeline\"\n)\n\nfunc (w *Source) listenAndServe(ctx context.Context, t *tomb.Tomb) error {\n\tw.logger.Infof(\"%d appsec runner to start\", len(w.AppsecRunners))\n\n\tserverError := make(chan error, 2)\n\n\tstartServer := func(listener net.Listener, canTLS bool) {\n\t\tvar err error\n\n\t\tif canTLS && (w.config.CertFilePath != \"\" || w.config.KeyFilePath != \"\") {\n\t\t\tif w.config.KeyFilePath == \"\" {\n\t\t\t\tserverError <- errors.New(\"missing TLS key file\")\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif w.config.CertFilePath == \"\" {\n\t\t\t\tserverError <- errors.New(\"missing TLS cert file\")\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\terr = w.server.ServeTLS(listener, w.config.CertFilePath, w.config.KeyFilePath)\n\t\t} else {\n\t\t\terr = w.server.Serve(listener)\n\t\t}\n\n\t\tswitch {\n\t\tcase errors.Is(err, http.ErrServerClosed):\n\t\t\tbreak\n\t\tcase err != nil:\n\t\t\tserverError <- err\n\t\t}\n\t}\n\n\tlistenConfig := &net.ListenConfig{}\n","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/acquisition/modules/appsec/run.go#L19-L55","documentation":"Mirror of the key-file check: when either TLS path is set, both are required. A cert_file that is empty while key_file is present causes the server startup to abort with this error before ServeTLS is called.","triggerScenarios":"startServer runs with w.config.KeyFilePath set but w.config.CertFilePath empty — key_file given without cert_file in the appsec datasource config.","commonSituations":"Configuring TLS on the appsec listener and providing only the key; typoed cert_file key; certificate file removed by secret rotation while key remained.","solutions":["Add the cert_file path alongside key_file in the config","Confirm the certificate file exists and is readable by the crowdsec process","Remove both cert_file and key_file to intentionally run plain HTTP"],"exampleFix":"// before\nsource: appsec\n key_file: /etc/ssl/crowdsec/tls.key\n// after\nsource: appsec\n cert_file: /etc/ssl/crowdsec/tls.cert\n key_file: /etc/ssl/crowdsec/tls.key","handlingStrategy":"validation","validationCode":"if (cfg.CertFilePath != \"\" || cfg.KeyFilePath != \"\") && cfg.CertFilePath == \"\" {\n    return errors.New(\"key_file set without cert_file\")\n}","typeGuard":null,"tryCatchPattern":"go func() {\n    if err := <-serverError; err != nil {\n        if strings.Contains(err.Error(), \"missing TLS cert\") { /* fix cert/key pair in config */ }\n    }\n}()","preventionTips":["Configure TLS cert and key together","Watch serverError channel output during startup","Check secret mounts for partial cert/key provisioning"],"tags":["appsec","tls","configuration","https"],"backgroundTag":"missing-required-config-field","analyzedSha":"909b5157986a2b2c2163300fdaef5ed01289f7d2","analyzedAt":"2026-09-06T12:27:26.012Z","contentChangedAt":"2026-09-06T12:27:26.012Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}