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
Returned by the SPIFFE verify callback when the rawCerts slice received from the peer is empty (bundle.go:171). With InsecureSkipVerify=true and a custom VerifyPeerCertificate, an empty chain means there is nothing to validate, so the handshake fails fast rather than silently succeeding.
Solutions
- Ensure the xDS management server is configured for mTLS and will present its certificate chain.
- If the deployment intentionally uses one-way TLS, remove the spiffe_trust_bundle_map_file from the bootstrap so the standard RootCAs path is used.
- Check for TLS-terminating proxies in the path and reconfigure them to passthrough or to present the upstream chain.
Defensive patterns
Strategy: try-catch
Try / catch
// Distinguish 'no cert sent' from other handshake errors:
if err != nil && strings.Contains(err.Error(), "has no valid input certificates") {
// server did not present a certificate; check mTLS config
} Prevention
- Verify the server requires client certs and presents its own cert.
- Use openssl s_client to confirm the server chain is presented before pointing xDS at it.
- Ensure no TLS-terminating proxy strips the peer certificate.
When it happens
Trigger: The TLS handshake completes at the record layer but the peer supplied zero certificates. This happens during ClientHandshake when the server does not present a chain (e.g. server uses PSK or is misconfigured to not request/send a certificate) and a SPIFFE bundle map is in use.
Common situations: Server is configured for one-way TLS but client expects mTLS; server certificate selection fails silently; intermediary (load balancer, sidecar) terminates TLS and does not forward the peer cert; wrong port reached.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- spiffe: verify function could not parse input certificate
- spiffe: x509 certificate Verify failed
- xds: no peer certificates presented
- overriding server name is not supported by xDS client TLS…
- security configuration on the client-side does not contain…
AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11).
Data as JSON: /api/errors/8d3d48b27b0f2ece.
Report an issue: GitHub.
Appendix: 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 0c51461d27)