{"record":{"id":"97b725b80b8c492d","repo":"temporalio/temporal","slug":"cert-or-key-is-missing","errorCode":null,"errorMessage":"cert or key is missing","messagePattern":"cert or key is missing","errorType":"validation","errorClass":"ErrTLSConfig","httpStatus":null,"severity":"error","filePath":"common/auth/tls_config_helper.go","lineNumber":131,"sourceCode":"\t\ttlsConfig.Certificates = []tls.Certificate{*clientCert}\n\t}\n\n\treturn tlsConfig, nil\n}\n\nfunc validateTemporalTls(temporalTls *TLS) error {\n\tif temporalTls.CertData != \"\" && temporalTls.CertFile != \"\" {\n\t\treturn fmt.Errorf(\"%w: %s\", ErrTLSConfig, \"only one of certData or certFile properties should be specified\")\n\t}\n\n\tif temporalTls.KeyData != \"\" && temporalTls.KeyFile != \"\" {\n\t\treturn fmt.Errorf(\"%w: %s\", ErrTLSConfig, \"only one of keyData or keyFile properties should be specified\")\n\t}\n\n\tcertProvided := temporalTls.CertData != \"\" || temporalTls.CertFile != \"\"\n\tkeyProvided := temporalTls.KeyData != \"\" || temporalTls.KeyFile != \"\"\n\tif certProvided != keyProvided {\n\t\treturn fmt.Errorf(\"%w: %s\", ErrTLSConfig, \"cert or key is missing\")\n\t}\n\n\tif temporalTls.CaData != \"\" && temporalTls.CaFile != \"\" {\n\t\treturn fmt.Errorf(\"%w: %s\", ErrTLSConfig, \"only one of caData or caFile properties should be specified\")\n\t}\n\treturn nil\n}\n\nfunc parseCAs(temporalTls *TLS) (*x509.CertPool, error) {\n\tvar caBytes []byte\n\tvar err error\n\tif temporalTls.CaFile != \"\" {\n\t\tcaBytes, err = os.ReadFile(temporalTls.CaFile)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"%w: %s (%w)\", ErrTLSConfig, \"unable to read client ca file\", err)\n\t\t}\n\t} else if temporalTls.CaData != \"\" {\n\t\tcaBytes, err = base64.StdEncoding.DecodeString(temporalTls.CaData)","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/common/auth/tls_config_helper.go#L113-L149","documentation":"This error is returned by validateTemporalTls when a certificate is provided without a matching private key, or vice versa: certProvided != keyProvided. A usable mTLS identity requires both, so the library rejects the partial config and wraps it with ErrTLSConfig.","triggerScenarios":"Calling NewTLSConfig where one side is set — e.g. CertFile set but neither KeyData nor KeyFile, or KeyData set with no CertData/CertFile.","commonSituations":"Config templating where the key is injected separately from the cert (and one injection fails); someone commenting out the key field; rotating certs and replacing only one half of the pair; mounting only the cert secret in Kubernetes.","solutions":["Add the missing counterpart: set both cert (CertData or CertFile) and key (KeyData or KeyFile).","If mTLS identity is not needed, remove the cert/key fields entirely rather than leaving only one.","Verify secret/file mounts so both halves of the pair are delivered to the process."],"exampleFix":"// before\ntls:\n  certFile: \"/etc/temporal/certs/client.pem\"\n// after\ntls:\n  certFile: \"/etc/temporal/certs/client.pem\"\n  keyFile: \"/etc/temporal/certs/client.key\"","handlingStrategy":"validation","validationCode":"func validateTLSPair(t *auth.TLS) error {\n\tcert := t.CertData != \"\" || t.CertFile != \"\"\n\tkey := t.KeyData != \"\" || t.KeyFile != \"\"\n\tif cert != key {\n\t\treturn fmt.Errorf(\"TLS cert and key must both be provided together\")\n\t}\n\treturn nil\n}","typeGuard":"func hasCompleteIdentity(t *auth.TLS) bool {\n\tcert := t.CertData != \"\" || t.CertFile != \"\"\n\tkey := t.KeyData != \"\" || t.KeyFile != \"\"\n\treturn cert == key\n}","tryCatchPattern":null,"preventionTips":["Always store cert+key as a pair in the same secret/mount and template them together","During rotation, update both halves in one operation","Add a startup assertion that cert and key presence match before calling NewTLSConfig"],"tags":["tls","config","validation"],"backgroundTag":"tls-cert-key-mismatch","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}