golang/go · error

tls: client didn't provide a certificate

Error message

tls: client didn't provide a certificate

What it means

The server requires a client certificate (ClientAuth is RequireAnyClientCert or RequireAndVerifyClientCert) but the client sent an empty certificate list. The server aborts with certificate_required (TLS 1.3) or handshake_failure (TLS 1.2).

Source

Thrown at src/crypto/tls/handshake_server.go:967

			c.sendAlert(alertDecodeError)
			return errors.New("tls: failed to parse client certificate: " + err.Error())
		}
		if certs[i].PublicKeyAlgorithm == x509.RSA {
			n := certs[i].PublicKey.(*rsa.PublicKey).N.BitLen()
			if max, ok := checkKeySize(n); !ok {
				c.sendAlert(alertBadCertificate)
				return fmt.Errorf("tls: client sent certificate containing RSA key larger than %d bits", max)
			}
		}
	}

	if len(certs) == 0 && requiresClientCert(c.config.ClientAuth) {
		if c.vers == VersionTLS13 {
			c.sendAlert(alertCertificateRequired)
		} else {
			c.sendAlert(alertHandshakeFailure)
		}
		return errors.New("tls: client didn't provide a certificate")
	}

	if c.config.ClientAuth >= VerifyClientCertIfGiven && len(certs) > 0 {
		opts := x509.VerifyOptions{
			Roots:         c.config.ClientCAs,
			CurrentTime:   c.config.time(),
			Intermediates: x509.NewCertPool(),
			KeyUsages:     []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
		}

		for _, cert := range certs[1:] {
			opts.Intermediates.AddCert(cert)
		}

		chains, err := certs[0].Verify(opts)
		if err != nil {
			if _, ok := errors.AsType[x509.UnknownAuthorityError](err); ok {
				c.sendAlert(alertUnknownCA)

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Provision the client with a certificate/key pair and configure tls.Config.Certificates or GetClientCertificate.
  2. If the client genuinely has no cert, relax the server's ClientAuth to VerifyClientCertIfGiven or NoClientCert.
  3. Ensure the client library honors the CertificateRequest callback.
  4. Distribute the client certificate and key via your secrets manager or config pipeline.

Example fix

// before: client has no certificate configured
http.Client{Transport: &http.Transport{
    TLSClientConfig: &tls.Config{}, // no Certificates
}}

// after: load the mTLS client certificate
cert, err := tls.LoadX509KeyPair("client.crt", "client.key")
if err != nil { return err }
http.Client{Transport: &http.Transport{
    TLSClientConfig: &tls.Config{
        Certificates: []tls.Certificate{cert},
    },
}}
Defensive patterns

Strategy: validation

Validate before calling

// Client: ensure a certificate is configured before connecting to an mTLS
// server.
if len(cfg.Certificates) == 0 && cfg.GetClientCertificate == nil {
    return errors.New("server requires mTLS; no client certificate configured")
}

Try / catch

// Client: catch and prompt for / load a certificate.
if err != nil && strings.Contains(err.Error(), "didn't provide a certificate") {
    cert, lerr := loadClientCert()
    if lerr != nil { return err }
    cfg.Certificates = []tls.Certificate{cert}
    // retry
}

Prevention

When it happens

Trigger: requiresClientCert(c.config.ClientAuth) is true and len(certs) == 0 — the client responded to CertificateRequest with an empty Certificate message.

Common situations: The client has no certificate configured, ignores the server's CertificateRequest, is not prompted to select one, or its mTLS configuration is missing. Common when server-side mTLS policy is newly enforced but clients have not been updated.

Understand the failure class

Related errors


AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12). Data as JSON: /api/errors/09b2fa58dbcd9f96. Report an issue: GitHub.