golang/go · error

tls: failed to parse certificate from server: {err}

Error message

tls: failed to parse certificate from server: {err}

What it means

Thrown in verifyServerCertificate() when the ASN.1/DER-encoded certificate bytes from the server's Certificate handshake message cannot be parsed into a valid x509.Certificate. The wrapped error string contains the specific x509 parse failure reason.

Source

Thrown at src/crypto/tls/handshake_client.go:1111

		if max, err := strconv.Atoi(v); err == nil {
			if (n <= max) != (n <= defaultMaxRSAKeySize) {
				tlsmaxrsasize.IncNonDefault()
			}
			return max, n <= max
		}
	}
	return defaultMaxRSAKeySize, n <= defaultMaxRSAKeySize
}

// verifyServerCertificate parses and verifies the provided chain, setting
// c.verifiedChains and c.peerCertificates or sending the appropriate alert.
func (c *Conn) verifyServerCertificate(certificates [][]byte) error {
	certs := make([]*x509.Certificate, len(certificates))
	for i, asn1Data := range certificates {
		cert, err := globalCertCache.newCert(asn1Data)
		if err != nil {
			c.sendAlert(alertDecodeError)
			return errors.New("tls: failed to parse certificate from server: " + err.Error())
		}
		if cert.PublicKeyAlgorithm == x509.RSA {
			n := cert.PublicKey.(*rsa.PublicKey).N.BitLen()
			if max, ok := checkKeySize(n); !ok {
				c.sendAlert(alertBadCertificate)
				return fmt.Errorf("tls: server sent certificate containing RSA key larger than %d bits", max)
			}
		}
		certs[i] = cert
	}

	echRejected := c.config.EncryptedClientHelloConfigList != nil && !c.echAccepted
	if echRejected {
		if c.config.EncryptedClientHelloRejectionVerify != nil {
			if err := c.config.EncryptedClientHelloRejectionVerify(c.connectionStateLocked()); err != nil {
				c.sendAlert(alertBadCertificate)
				return err
			}

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Inspect the full error string — the appended {err} describes the exact x509/ASN.1 parse failure (e.g. 'x509: malformed certificate').
  2. Verify the server certificate with: openssl s_client -connect host:443 -showcerts
  3. If behind a TLS-terminating proxy, ensure it correctly forwards the upstream certificate chain without modification.
  4. Check for network corruption — test with a direct connection bypassing proxies or VPNs.
  5. Try a different Go version — x509 parsing strictness has changed across releases.
Defensive patterns

Strategy: try-catch

Try / catch

// Certificate parse errors are untyped — match by prefix
conn, err := tls.Dial("tcp", addr, config)
if err != nil {
    if strings.Contains(err.Error(), "failed to parse certificate from server") {
        log.Printf("Server certificate is malformed or corrupted: %v", err)
        // Inspect with openssl s_client -connect host:443 -showcerts
        // Check for proxy/MTU issues
    }
    return err
}

Prevention

When it happens

Trigger: Triggered when globalCertCache.newCert(asn1Data) returns a non-nil error for any certificate in the server's chain. The client sends alertDecodeError and returns the error with the underlying parse failure appended.

Common situations: Corrupted or truncated certificate data in transit. Server sending a non-X.509 certificate format. MITM proxy or TLS-terminating load balancer mangling certificate bytes. Network MTU issues truncating the handshake message. Server sending a certificate chain with invalid DER encoding.

Understand the failure class

Related errors


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