{"record":{"id":"d0e88f88e78e519f","repo":"grpc/grpc-go","slug":"xds-no-peer-certificates-presented","errorCode":null,"errorMessage":"xds: no peer certificates presented","messagePattern":"xds: no peer certificates presented","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/credentials/xds/handshake_info.go","lineNumber":256,"sourceCode":"\n\tif hi.identityProvider != nil {\n\t\tkm, err := hi.identityProvider.KeyMaterial(ctx)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"xds: fetching identity certificates from CertificateProvider failed: %v\", err)\n\t\t}\n\t\tcfg.Certificates = km.Certs\n\t}\n\n\tif envconfig.XDSSNIEnabled && sni != \"\" {\n\t\tcfg.ServerName = sni\n\t}\n\treturn cfg, nil\n}\n\nfunc (hi *HandshakeInfo) buildVerifyFunc(km *certprovider.KeyMaterial, isClient bool, sni string) func(rawCerts [][]byte, _ [][]*x509.Certificate) error {\n\treturn func(rawCerts [][]byte, _ [][]*x509.Certificate) error {\n\t\tif len(rawCerts) == 0 {\n\t\t\treturn fmt.Errorf(\"xds: no peer certificates presented\")\n\t\t}\n\t\t// Parse all raw certificates presented by the peer.\n\t\tvar certs []*x509.Certificate\n\t\tfor _, rc := range rawCerts {\n\t\t\tcert, err := x509.ParseCertificate(rc)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tcerts = append(certs, cert)\n\t\t}\n\n\t\t// Build the intermediates list and verify that the leaf certificate is\n\t\t// signed by one of the root certificates. If a SPIFFE Bundle Map is\n\t\t// configured, it is used to get the root certs. Otherwise, the\n\t\t// configured roots in the root provider are used.\n\t\tintermediates := x509.NewCertPool()\n\t\tfor _, cert := range certs[1:] {\n\t\t\tintermediates.AddCert(cert)","sourceCodeStart":238,"sourceCodeEnd":274,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/internal/credentials/xds/handshake_info.go#L238-L274","documentation":"Returned by the custom peer-cert verifier (buildVerifyFunc) when the peer presented zero raw certificates during the TLS handshake. Because InsecureSkipVerify is set so gRPC can run its own verification, an empty chain is caught explicitly here rather than by the stdlib. This typically means the peer sent a TLS alert instead of a certificate.","triggerScenarios":"buildVerifyFunc at handshake_info.go:255 receives rawCerts of length 0. Happens on the server when the client connects without a certificate while the server still wires up a VerifyPeerCertificate callback, or when the peer aborts the handshake early.","commonSituations":"Client misconfiguration (no client cert in an mTLS-required setup); network middlebox that strips the cert; client using TLS (not mTLS) against a server that configured tls.RequireAnyClientCert + custom verify; peer crashed mid-handshake.","solutions":["Ensure the client is configured with a certificate when the server expects mTLS.","Confirm the client's identityProvider is producing certs (see errors 250/254).","If one-way TLS is intended, do not set requireClientCert or the SPIFFE verify callback on the server.","Check for a middlebox or proxy terminating TLS before traffic reaches the gRPC server."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := verifyPeer(rawCerts); err != nil {\n    if strings.Contains(err.Error(), \"no peer certificates presented\") {\n        // client did not send a cert; fail closed unless one-way TLS is intended\n    }\n}","preventionTips":["Do not enable RequireAnyClientCert / SPIFFE verify on listeners serving one-way TLS clients.","Verify client configurations include a certificate before requiring mTLS server-side.","Watch for middleboxes that strip TLS and present no cert."],"tags":["grpc","xds","mtls","handshake","certificate"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}