{"record":{"id":"68f8cfdbd5bc1aa0","repo":"grpc/grpc-go","slug":"serverhandshake-is-not-supported-for-client-creden","errorCode":null,"errorMessage":"ServerHandshake is not supported for client credentials","messagePattern":"ServerHandshake is not supported for client credentials","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"credentials/xds/xds.go","lineNumber":161,"sourceCode":"\t\t}\n\tcase <-ctx.Done():\n\t\tconn.Close()\n\t\treturn nil, nil, ctx.Err()\n\t}\n\tinfo := credentials.TLSInfo{\n\t\tState: conn.ConnectionState(),\n\t\tCommonAuthInfo: credentials.CommonAuthInfo{\n\t\t\tSecurityLevel: credentials.PrivacyAndIntegrity,\n\t\t},\n\t\tSPIFFEID: credinternal.SPIFFEIDFromState(conn.ConnectionState()),\n\t}\n\treturn credinternal.WrapSyscallConn(rawConn, conn), info, nil\n}\n\n// ServerHandshake performs the TLS handshake on the server-side.\nfunc (c *credsImpl) ServerHandshake(rawConn net.Conn) (net.Conn, credentials.AuthInfo, error) {\n\tif c.isClient {\n\t\treturn nil, nil, errors.New(\"ServerHandshake is not supported for client credentials\")\n\t}\n\n\t// An xds-enabled gRPC server wraps the underlying raw net.Conn in a type\n\t// that provides a way to retrieve `HandshakeInfo`, which contains the\n\t// certificate providers to be used during the handshake. If the net.Conn\n\t// passed to this function does not implement this interface, or if the\n\t// `HandshakeInfo` does not contain the information we are looking for, we\n\t// delegate the handshake to the fallback credentials.\n\thiConn, ok := rawConn.(interface {\n\t\tXDSHandshakeInfo() (*grpcsync.RefCounted[xdsinternal.HandshakeInfo], error)\n\t})\n\tif !ok {\n\t\treturn c.fallback.ServerHandshake(rawConn)\n\t}\n\thi, err := hiConn.XDSHandshakeInfo()\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/credentials/xds/xds.go#L143-L179","documentation":"Returned by credsImpl.ServerHandshake when the credentials were created for client-side use (NewClientCredentials) but ServerHandshake is called on them. This is the mirror of the client-handshake guard: xDS credentials are directional and the isClient flag is true, so the guard at line 160-161 fires.","triggerScenarios":"A credentials instance created via xds.NewClientCredentials is passed to grpc.NewServer (which calls ServerHandshake), or is otherwise used in a server context.","commonSituations":"Developers pass client credentials to a gRPC server, often by sharing or mislabeling a credential variable. Also occurs in bidirectional test setups that reuse one credential object.","solutions":["Use xds.NewServerCredentials for grpc.NewServer and xds.NewClientCredentials for grpc.Dial.","Separate client and server credential construction into distinct functions or variables to prevent confusion."],"exampleFix":"// before\nclientCreds, _ := xds.NewClientCredentials(opts)\nsrv := grpc.NewServer(grpc.Creds(clientCreds)) // error\n// after\nserverCreds, _ := xds.NewServerCredentials(serverOpts)\nsrv := grpc.NewServer(grpc.Creds(serverCreds))","handlingStrategy":"validation","validationCode":"// Ensure server-side xDS credentials are used for NewServer:\nserverCreds, err := xds.NewServerCredentials(serverOpts)\nif err != nil { return err }\nsrv := grpc.NewServer(grpc.Creds(serverCreds))","typeGuard":"// No public field to check; prevent misuse by isolating server credential construction.","tryCatchPattern":null,"preventionTips":["Never pass client credentials to grpc.NewServer.","Keep server credential construction in the server setup function only.","Review test harnesses that reuse credential objects."],"tags":["go","grpc","xds","credentials","misuse"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}