grpc/grpc-go · error

spiffe: verify function has no valid input certificates

Error message

spiffe: verify function has no valid input certificates

What it means

After parsing all raw cert blobs, the SPIFFE verify callback checks that at least one certificate was provided (bundle.go:170-171). If the rawCerts slice is empty — meaning the server sent no certificates during the handshake — verification cannot proceed and this error is returned.

Source

Thrown at internal/xds/bootstrap/tlscreds/bundle.go:171

	return errors.New("overriding server name is not supported by xDS client TLS credentials")
}

func (c *reloadingCreds) ServerHandshake(net.Conn) (net.Conn, credentials.AuthInfo, error) {
	return nil, nil, errors.New("server handshake is not supported by xDS client TLS credentials")
}

func buildSPIFFEVerifyFunc(spiffeBundleMap map[string]*spiffebundle.Bundle) func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
	return func(rawCerts [][]byte, _ [][]*x509.Certificate) error {
		rawCertList := make([]*x509.Certificate, len(rawCerts))
		for i, asn1Data := range rawCerts {
			cert, err := x509.ParseCertificate(asn1Data)
			if err != nil {
				return fmt.Errorf("spiffe: verify function could not parse input certificate: %v", err)
			}
			rawCertList[i] = cert
		}
		if len(rawCertList) == 0 {
			return fmt.Errorf("spiffe: verify function has no valid input certificates")
		}
		leafCert := rawCertList[0]
		roots, err := spiffe.GetRootsFromSPIFFEBundleMap(spiffeBundleMap, leafCert)
		if err != nil {
			return err
		}

		opts := x509.VerifyOptions{
			Roots:         roots,
			CurrentTime:   time.Now(),
			Intermediates: x509.NewCertPool(),
		}

		for _, cert := range rawCertList[1:] {
			opts.Intermediates.AddCert(cert)
		}
		// The verified chain is (surprisingly) unused.
		if _, err = rawCertList[0].Verify(opts); err != nil {

View on GitHub (pinned to 03255a9237)

Solutions

  1. Ensure the xDS management server is configured to present a server certificate.
  2. Remove any TLS-terminating intermediary that strips certificates, or configure it to forward the origin cert.
  3. If SPIFFE is not required, remove spiffe_trust_bundle_map_file from the bootstrap so standard RootCA verification is used instead.

Example fix

# verify the server presents a certificate:
#   openssl s_client -connect xds-server:443
# should show 'Server certificate' and the chain;
# if absent, reconfigure the server's TLS cert
Defensive patterns

Strategy: try-catch

Validate before calling

// Confirm the server sends at least one certificate.
func ensureServerSendsCert(addr string) error {
    conf := &tls.Config{InsecureSkipVerify: true}
    conn, err := tls.Dial("tcp", addr, conf)
    if err != nil { return err }
    defer conn.Close()
    if len(conn.ConnectionState().PeerCertificates) == 0 {
        return errors.New("server sends no certificate")
    }
    return nil
}

Try / catch

if err := creds.ClientHandshake(ctx, authority, conn); err != nil {
    if strings.Contains(err.Error(), "no valid input certificates") {
        // server misconfigured: not presenting a cert; escalate
    }
    return err
}

Prevention

When it happens

Trigger: The server completed the TLS handshake but provided zero certificates. The verify callback receives an empty rawCerts slice, so rawCertList ends up empty.

Common situations: The xDS server is misconfigured to not send a certificate; a load balancer or TLS offloader in front of the server strips the certificate; an anonymized/TLS-PSK setup that does not use certificates; SPIFFE verification enabled against a non-SPIFFE server.

Understand the failure class

Related errors


AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07). Data as JSON: /api/errors/8d3d48b27b0f2ece. Report an issue: GitHub.