{"record":{"id":"fc3900835147e349","repo":"fatedier/frp","slug":"xtcp-is-not-supported-in-frps","errorCode":null,"errorMessage":"xtcp is not supported in frps","messagePattern":"xtcp is not supported in frps","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/proxy/xtcp.go","lineNumber":55,"sourceCode":"}\n\nfunc NewXTCPProxy(baseProxy *BaseProxy) Proxy {\n\tunwrapped, ok := baseProxy.GetConfigurer().(*v1.XTCPProxyConfig)\n\tif !ok {\n\t\treturn nil\n\t}\n\treturn &XTCPProxy{\n\t\tBaseProxy: baseProxy,\n\t\tcfg:       unwrapped,\n\t\tcloseCh:   make(chan struct{}),\n\t}\n}\n\nfunc (pxy *XTCPProxy) Run() (remoteAddr string, err error) {\n\txl := pxy.xl\n\n\tif pxy.rc.NatHoleController == nil {\n\t\terr = fmt.Errorf(\"xtcp is not supported in frps\")\n\t\treturn\n\t}\n\tallowUsers := pxy.cfg.AllowUsers\n\t// if allowUsers is empty, only allow same user from proxy\n\tif len(allowUsers) == 0 {\n\t\tallowUsers = []string{pxy.GetUserInfo().User}\n\t}\n\tsidCh, err := pxy.rc.NatHoleController.ListenClient(pxy.GetName(), pxy.cfg.Secretkey, allowUsers)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tgo func() {\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-pxy.closeCh:\n\t\t\t\treturn\n\t\t\tcase sid := <-sidCh:\n\t\t\t\tworkConn, errRet := pxy.GetWorkConnFromPool(nil, nil)","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/fatedier/frp/blob/6c8a8d0a97d03b44e9528d30b30c70cb9d61b405/server/proxy/xtcp.go#L37-L73","documentation":"XTCPProxy.Run refuses to start when the server's NatHoleController is nil, meaning frps is running without NAT hole-punching support. The controller is normally created at service startup, so a nil value means its creation failed or was skipped in this build/config. The xtcp proxy request from the client is rejected and the proxy closes.","triggerScenarios":"Client declares an xtcp proxy while frps failed to initialize the nathole controller at boot (see \"create nat hole controller error\" in server logs); an embedded/custom frps built without nathole support.","commonSituations":"Server logs contain an earlier nathole.NewController failure (e.g. UDP socket issues) that went unnoticed; running xtcp against a restricted container/host where the controller cannot bind; version of frps where the controller is optional.","solutions":["Inspect frps startup logs for \"create nat hole controller error\" and fix that root cause first","If NAT hole punching cannot be supported on that host, remove the xtcp proxies or switch them to type = \"stcp\"+\"sudp\" style visiting","Restart frps after fixing the environment so the controller is created"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if _, err := pxy.Run(); err != nil && strings.Contains(err.Error(), \"xtcp is not supported\") {\n    // server lacks NAT hole punching: degrade to stcp+sudp instead of retrying\n}","preventionTips":["Verify at startup that frps created its nat hole controller (check boot logs) before deploying xtcp proxies","Keep an stcp fallback config for environments where UDP hole punching is blocked"],"tags":["frps","xtcp","nathole","p2p"],"backgroundTag":null,"analyzedSha":"6c8a8d0a97d03b44e9528d30b30c70cb9d61b405","analyzedAt":"2026-08-15T06:53:27.215Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}