{"record":{"id":"a473c20b3e5be62c","repo":"cilium/cilium","slug":"certificate-and-private-key-are-both-required-but-a473c2","errorCode":null,"errorMessage":"certificate and private key are both required, but only one was provided","messagePattern":"certificate and private key are both required, but only one was provided","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/crypto/certloader/reloader.go","lineNumber":37,"sourceCode":"type FileReloader struct {\n\t// caFiles, certFile, and privkeyFile are constants for the FileReloader's\n\t// lifetime, thus accessing them doesn't require acquiring the mutex.\n\tcaFiles     []string\n\tcertFile    string\n\tprivkeyFile string\n\tmutex       lock.Mutex\n\t// fields below should only be accessed with mutex acquired as they may be\n\t// updated concurrently.\n\tcaCertPool           *x509.CertPool\n\tcaCertPoolGeneration uint // incremented when caCertPool is reloaded\n\tkeypair              *tls.Certificate\n\tkeypairGeneration    uint // incremented when keypair is reloaded\n}\n\nvar (\n\t// ErrInvalidKeypair is returned when either the certificate or its\n\t// corresponding private key is missing.\n\tErrInvalidKeypair = errors.New(\"certificate and private key are both required, but only one was provided\")\n)\n\n// NewFileReloaderReady create and returns a FileReloader using the given file.\n// The files are already loaded when this function returns, thus the returned\n// FileReloader is readily usable.\nfunc NewFileReloaderReady(caFiles []string, certFile, privkeyFile string) (*FileReloader, error) {\n\tr, err := NewFileReloader(caFiles, certFile, privkeyFile)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// load the files for the first time.\n\tif _, _, err := r.Reload(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn r, nil\n}","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/cilium/cilium/blob/ac7b90affa4baf0642e6685319d56907b3a73a6d/pkg/crypto/certloader/reloader.go#L19-L55","documentation":"ErrInvalidKeypair in pkg/crypto/certloader/reloader.go is returned when constructing a FileReloader (NewFileReloader, via NewFileReloaderReady) when exactly one of the certificate and private key files is provided but not the other. The certloader requires the pair to be complete; a lone cert or lone key cannot be used to establish TLS.","triggerScenarios":"Calling NewFileReloader/NewFileReloaderReady (used by validateMutualTLSFlags) with certFile set but privkeyFile empty, or privkeyFile set but certFile empty. Both empty may be allowed (non-mTLS); the mismatch is not.","commonSituations":"Incomplete Helm/CLI flags (e.g. setting --tls-cert but forgetting --tls-key); secret mounted with only one of the two files; typo in one file path causing the loader to see it as missing; partial Secret update in Kubernetes.","solutions":["Provide both certFile and privkeyFile (e.g. --tls-cert + --tls-key or the corresponding Helm values)","Verify the mounted Kubernetes Secret contains both tls.crt and tls.key entries","Fix the file path typo causing one of the pair to be missing","If you intend no TLS, clear both flags rather than only one"],"exampleFix":"// before\nreloader, err := certloader.NewFileReloader(nil, \"/certs/tls.crt\", \"\")\n// after\nreloader, err := certloader.NewFileReloader(nil, \"/certs/tls.crt\", \"/certs/tls.key\")","handlingStrategy":"validation","validationCode":"func validateKeypair(certFile, privkeyFile string) error {\n    if (certFile == \"\") != (privkeyFile == \"\") {\n        return certloader.ErrInvalidKeypair\n    }\n    if certFile != \"\" {\n        if _, err := os.Stat(certFile); err != nil { return err }\n        if _, err := os.Stat(privkeyFile); err != nil { return err }\n    }\n    return nil\n}","typeGuard":"func keypairComplete(certFile, privkeyFile string) bool { return (certFile == \"\") == (privkeyFile == \"\") }","tryCatchPattern":"r, err := certloader.NewFileReloader(caFiles, certFile, privkeyFile)\nif errors.Is(err, certloader.ErrInvalidKeypair) {\n    return fmt.Errorf(\"TLS keypair incomplete: cert=%q key=%q\", certFile, privkeyFile)\n}","preventionTips":["Always set cert and key flags as a pair (Helm values grouped together)","Mount Secrets containing both tls.crt and tls.key, and verify after mounting","Run flag validation (like validateMutualTLSFlags) before starting components","Watch for partial Secret updates in Kubernetes and re-sync volumes"],"tags":["cilium","tls","certificates","mtls","config-validation"],"backgroundTag":"incomplete-tls-keypair","analyzedSha":"ac7b90affa4baf0642e6685319d56907b3a73a6d","analyzedAt":"2026-08-31T18:27:15.868Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}