hashicorp/terraform · error

failed to append certs

Error message

failed to append certs

What it means

Returned by configureTLS (internal/backend/remote-state/http/backend.go:294) when tlsConfig.RootCAs.AppendCertsFromPEM([]byte(clientCACertificatePem)) returns false. AppendCertsFromPEM returns false when the provided PEM data contains no parseable certificates, so the http backend refuses to configure a trust store built from garbage. This only triggers when client_ca_certificate_pem (or TF_HTTP_CLIENT_CA_CERTIFICATE_PEM) is set.

Source

Thrown at internal/backend/remote-state/http/backend.go:294

		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")
		}
	}
	if clientCertificatePem != "" && clientPrivateKeyPem != "" {
		// attach a client certificate to the TLS handshake (aka mTLS)
		certificate, err := tls.X509KeyPair([]byte(clientCertificatePem), []byte(clientPrivateKeyPem))
		if err != nil {
			return fmt.Errorf("cannot load client certificate: %w", err)
		}
		tlsConfig.Certificates = []tls.Certificate{certificate}
	}

	return nil
}

func (b *Backend) StateMgr(name string) (statemgr.Full, tfdiags.Diagnostics) {
	var diags tfdiags.Diagnostics

	if name != backend.DefaultStateName {

View on GitHub (pinned to c9def3e214)

Solutions

  1. Provide the full, valid PEM-encoded CA certificate chain in client_ca_certificate_pem (BEGIN CERTIFICATE ... END CERTIFICATE).
  2. Validate the PEM decodes to at least one x509 certificate before configuring the backend.
  3. If the content is a path, read the file and inline its contents into the attribute.

Example fix

// before: malformed/empty CA pem
backend "http" {
  address                  = "https://state.example"
  client_ca_certificate_pem = ""
}

// after: full PEM body
backend "http" {
  address                  = "https://state.example"
  client_ca_certificate_pem = <<-EOT
-----BEGIN CERTIFICATE-----
MIIDazCCAlOgAwIBAgIUM...full CA cert...
-----END CERTIFICATE-----
EOT
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate the PEM before configuring the backend.
pool := x509.NewCertPool()
if !pool.AppendCertsFromPEM([]byte(caPem)) {
    return fmt.Errorf("client_ca_certificate_pem contains no parseable certificates")
}

Prevention

When it happens

Trigger: Configuring the http backend with client_ca_certificate_pem set to a value that is not valid PEM, is truncated, contains only a private key, or has non-certificate PEM blocks; or TF_HTTP_CLIENT_CA_CERTIFICATE_PEM pointing at malformed content.

Common situations: Pasting only the human-readable header of a CA cert; copying an intermediate/key instead of the CA; trailing/leading whitespace or encoding corruption from env var transport; using a file path instead of inline PEM content (the field expects the PEM text, not a path).

Related errors


AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07). Data as JSON: /api/errors/8c3320675d8c03b5. Report an issue: GitHub.