{"record":{"id":"c801f1bc20fb92e2","repo":"opentofu/opentofu","slug":"client-certificate-pem-is-set-but-client-private-k","errorCode":null,"errorMessage":"client_certificate_pem is set but client_private_key_pem is not","messagePattern":"client_certificate_pem is set but client_private_key_pem is not","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/backend/remote-state/http/backend.go","lineNumber":176,"sourceCode":"type Backend struct {\n\t*schema.Backend\n\tencryption encryption.StateEncryption\n\n\tclient *httpClient\n}\n\n// configureTLS configures TLS when needed; if there are no conditions requiring TLS, no change is made.\nfunc (b *Backend) configureTLS(client *retryablehttp.Client, data *schema.ResourceData) error {\n\t// If there are no conditions needing to configure TLS, leave the client untouched\n\tskipCertVerification := data.Get(\"skip_cert_verification\").(bool)\n\tclientCACertificatePem := data.Get(\"client_ca_certificate_pem\").(string)\n\tclientCertificatePem := data.Get(\"client_certificate_pem\").(string)\n\tclientPrivateKeyPem := data.Get(\"client_private_key_pem\").(string)\n\tif !skipCertVerification && clientCACertificatePem == \"\" && clientCertificatePem == \"\" && clientPrivateKeyPem == \"\" {\n\t\treturn nil\n\t}\n\tif clientCertificatePem != \"\" && clientPrivateKeyPem == \"\" {\n\t\treturn fmt.Errorf(\"client_certificate_pem is set but client_private_key_pem is not\")\n\t}\n\tif clientPrivateKeyPem != \"\" && clientCertificatePem == \"\" {\n\t\treturn fmt.Errorf(\"client_private_key_pem is set but client_certificate_pem is not\")\n\t}\n\n\t// TLS configuration is needed; create an object and configure it\n\tvar tlsConfig tls.Config\n\tclient.HTTPClient.Transport.(*http.Transport).TLSClientConfig = &tlsConfig\n\n\tif skipCertVerification {\n\t\t// ignores TLS verification\n\t\ttlsConfig.InsecureSkipVerify = true\n\t}\n\tif clientCACertificatePem != \"\" {\n\t\t// trust servers based on a CA\n\t\ttlsConfig.RootCAs = x509.NewCertPool()\n\t\tif !tlsConfig.RootCAs.AppendCertsFromPEM([]byte(clientCACertificatePem)) {\n\t\t\treturn errors.New(\"failed to append certs\")","sourceCodeStart":158,"sourceCodeEnd":194,"githubUrl":"https://github.com/opentofu/opentofu/blob/3561785c48c1ce615e7c50261bd351f26053efa2/internal/backend/remote-state/http/backend.go#L158-L194","documentation":"configureTLS requires the mTLS pair to be complete: if client_certificate_pem is non-empty while client_private_key_pem is empty, backend configuration aborts with this error before any TLS settings are applied. The two attributes are only meaningful together because tls.X509KeyPair consumes both.","triggerScenarios":"backend \"http\" config with client_certificate_pem set but client_private_key_pem omitted; passing the pair via repeated -backend-config flags where the key flag is missing or its attribute name is misspelled (e.g. client_private_key without the _pem suffix).","commonSituations":"Splitting cert and key into separate files/variables and forgetting the second -backend-config flag; merging config snippets where one side of the pair is dropped; renaming attributes during a migration to the _pem names.","solutions":["Add the matching client_private_key_pem attribute to the backend block","If you only meant to trust a custom CA, remove client_certificate_pem and keep client_ca_certificate_pem","Check attribute spelling when passing via -backend-config so the value does not silently read as empty"],"exampleFix":"# before\nbackend \"http\" {\n  address = \"https://state.example.com\"\n  client_certificate_pem = file(\"client.crt\")\n}\n# after\nbackend \"http\" {\n  address = \"https://state.example.com\"\n  client_certificate_pem = file(\"client.crt\")\n  client_private_key_pem = file(\"client.key\")\n}","handlingStrategy":"validation","validationCode":"// Pre-flight the mTLS pair before running tofu init\ncert := os.Getenv(\"TF_CLIENT_CERT\")\nkey := os.Getenv(\"TF_CLIENT_KEY\")\nif cert != \"\" && key == \"\" {\n    log.Fatal(\"client_certificate_pem is set but client_private_key_pem is missing\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat client_certificate_pem and client_private_key_pem as one unit in templates and reviews","Add a CI lint that fails when exactly one of the two attributes appears","Watch for _pem suffix typos when passing via -backend-config"],"tags":["http","backend","tls","mtls","configuration"],"backgroundTag":null,"analyzedSha":"3561785c48c1ce615e7c50261bd351f26053efa2","analyzedAt":"2026-08-15T23:27:16.226Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}