hashicorp/terraform · error
client_certificate_pem is set but client_private_key_pem is…
Error message
client_certificate_pem is set but client_private_key_pem is not
What it means
In configureTLS, client_certificate_pem (or TF_HTTP_CLIENT_CERTIFICATE_PEM) is non-empty while client_private_key_pem (or TF_HTTP_CLIENT_PRIVATE_KEY_PEM) is empty. mTLS requires BOTH a certificate and its matching private key; providing only the certificate is an incomplete, unusable configuration.
Solutions
- Set client_private_key_pem to the PEM private key matching the certificate.
- If you do not need mTLS, remove client_certificate_pem entirely.
- Verify both TF_HTTP_CLIENT_CERTIFICATE_PEM and TF_HTTP_CLIENT_PRIVATE_KEY_PEM are exported together.
Example fix
// before
client_certificate_pem = file("client.crt")
// client_private_key_pem missing
// after
client_certificate_pem = file("client.crt")
client_private_key_pem = file("client.key") Defensive patterns
Strategy: validation
Validate before calling
# Pre-flight: cert and key must both be set (or both unset)
cert="${TF_HTTP_CLIENT_CERTIFICATE_PEM:-}"
key="${TF_HTTP_CLIENT_PRIVATE_KEY_PEM:-}"
if [ -n "$cert" ] && [ -z "$key" ]; then
echo "ERROR: client_certificate_pem set but client_private_key_pem is empty"; exit 1
fi Prevention
- Always configure client_certificate_pem and client_private_key_pem as a pair.
- If mTLS is not needed, leave both unset rather than supplying only one.
- In CI, assert both TF_HTTP_CLIENT_*_PEM vars are exported together.
When it happens
Trigger: Certificate supplied via the backend block or env var, but the matching private key was omitted or its env var was not exported.
Common situations: Key lives in a different secret not wired into the pipeline; the key line was dropped during copy-paste; cert and key stored in separate stores and only one was referenced.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- client_private_key_pem is set but client_certificate_pem is…
- cannot load client certificate
- invalid retry_max
- invalid retry_wait_max
- invalid retry_wait_min
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/f51fd5d35518efe7.
Report an issue: GitHub.
Appendix: source
Thrown at internal/backend/remote-state/http/backend.go:276
backendbase.GetAttrDefault(configVal, "skip_cert_verification", cty.False),
)
clientCACertificatePem := backendbase.GetAttrEnvDefaultFallback(
configVal, "client_ca_certificate_pem",
"TF_HTTP_CLIENT_CA_CERTIFICATE_PEM", cty.StringVal(""),
).AsString()
clientCertificatePem := backendbase.GetAttrEnvDefaultFallback(
configVal, "client_certificate_pem",
"TF_HTTP_CLIENT_CERTIFICATE_PEM", cty.StringVal(""),
).AsString()
clientPrivateKeyPem := backendbase.GetAttrEnvDefaultFallback(
configVal, "client_private_key_pem",
"TF_HTTP_CLIENT_PRIVATE_KEY_PEM", cty.StringVal(""),
).AsString()
if !skipCertVerification && clientCACertificatePem == "" && clientCertificatePem == "" && clientPrivateKeyPem == "" {
return nil
}
if clientCertificatePem != "" && clientPrivateKeyPem == "" {
return fmt.Errorf("client_certificate_pem is set but client_private_key_pem is not")
}
if clientPrivateKeyPem != "" && clientCertificatePem == "" {
return fmt.Errorf("client_private_key_pem is set but client_certificate_pem is not")
}
// TLS configuration is needed; create an object and configure it
var tlsConfig tls.Config
client.HTTPClient.Transport.(*http.Transport).TLSClientConfig = &tlsConfig
if skipCertVerification {
// ignores TLS verification
tlsConfig.InsecureSkipVerify = true
}
if clientCACertificatePem != "" {
// trust servers based on a CA
tlsConfig.RootCAs = x509.NewCertPool()
if !tlsConfig.RootCAs.AppendCertsFromPEM([]byte(clientCACertificatePem)) {
return errors.New("failed to append certs")View on GitHub (pinned to d32a084675)