{"record":{"id":"f51fd5d35518efe7","repo":"hashicorp/terraform","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":276,"sourceCode":"\t\tbackendbase.GetAttrDefault(configVal, \"skip_cert_verification\", cty.False),\n\t)\n\tclientCACertificatePem := backendbase.GetAttrEnvDefaultFallback(\n\t\tconfigVal, \"client_ca_certificate_pem\",\n\t\t\"TF_HTTP_CLIENT_CA_CERTIFICATE_PEM\", cty.StringVal(\"\"),\n\t).AsString()\n\tclientCertificatePem := backendbase.GetAttrEnvDefaultFallback(\n\t\tconfigVal, \"client_certificate_pem\",\n\t\t\"TF_HTTP_CLIENT_CERTIFICATE_PEM\", cty.StringVal(\"\"),\n\t).AsString()\n\tclientPrivateKeyPem := backendbase.GetAttrEnvDefaultFallback(\n\t\tconfigVal, \"client_private_key_pem\",\n\t\t\"TF_HTTP_CLIENT_PRIVATE_KEY_PEM\", cty.StringVal(\"\"),\n\t).AsString()\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":258,"sourceCodeEnd":294,"githubUrl":"https://github.com/hashicorp/terraform/blob/c9def3e214014c1188faabfc4a5bde5095139765/internal/backend/remote-state/http/backend.go#L258-L294","documentation":"In configureTLS, when client_certificate_pem is non-empty (or TF_HTTP_CLIENT_CERTIFICATE_PEM set) but client_private_key_pem is empty. mTLS requires both halves of the key pair, so supplying only the certificate is treated as a configuration error rather than silently sending an unverifiable cert. Fires at Configure time before any TLS handshake.","triggerScenarios":"Setting client_certificate_pem without client_private_key_pem in the backend block, or exporting only TF_HTTP_CLIENT_CERTIFICATE_PEM. Triggered at `terraform init` once a TLS-related option is present.","commonSituations":"Operator's secret store issues only the cert; copy-paste drops the key block; key is injected by a separate mechanism that forgot the env var.","solutions":["Provide a matching client_private_key_pem (PEM-encoded) alongside the certificate.","If mTLS is not actually required, remove client_certificate_pem entirely.","Ensure both env vars (TF_HTTP_CLIENT_CERTIFICATE_PEM and TF_HTTP_CLIENT_PRIVATE_KEY_PEM) are set together in CI."],"exampleFix":"// before\nbackend \"http\" {\n  address               = \"https://state.corp\"\n  client_certificate_pem = file(\"client.crt\")\n}\n// after\nbackend \"http\" {\n  address                = \"https://state.corp\"\n  client_certificate_pem = file(\"client.crt\")\n  client_private_key_pem = file(\"client.key\")\n}","handlingStrategy":"validation","validationCode":"func validateMTLSPair(cert, key string) error {\n  if cert != \"\" && key == \"\" {\n    return fmt.Errorf(\"client_certificate_pem set without client_private_key_pem\")\n  }\n  return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Provision cert+key as a pair in the same secret.","In CI set both TF_HTTP_CLIENT_CERTIFICATE_PEM and TF_HTTP_CLIENT_PRIVATE_KEY_PEM together.","Unit-test config generation to assert both-or-neither."],"tags":["config","mtls","tls","http-backend","terraform"],"analyzedSha":"c9def3e214014c1188faabfc4a5bde5095139765","analyzedAt":"2026-08-07T15:39:49.278Z","schemaVersion":2},"datasetVersion":"2026-08-07T20:17:04.800Z"}