{"record":{"id":"af3b7da3b18bd75b","repo":"fatedier/frp","slug":"dial-udp-error-v","errorCode":null,"errorMessage":"dial udp error: %v","messagePattern":"dial udp error: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/visitor/xtcp.go","lineNumber":342,"sourceCode":"\tClose()\n}\n\ntype KCPTunnelSession struct {\n\tsession *fmux.Session\n\tlConn   *net.UDPConn\n\tmu      sync.RWMutex\n}\n\nfunc NewKCPTunnelSession() TunnelSession {\n\treturn &KCPTunnelSession{}\n}\n\nfunc (ks *KCPTunnelSession) Init(listenConn *net.UDPConn, raddr *net.UDPAddr) error {\n\tlistenConn.Close()\n\tladdr, _ := net.ResolveUDPAddr(\"udp\", listenConn.LocalAddr().String())\n\tlConn, err := net.DialUDP(\"udp\", laddr, raddr)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"dial udp error: %v\", err)\n\t}\n\tremote, err := netpkg.NewKCPConnFromUDP(lConn, true, raddr.String())\n\tif err != nil {\n\t\tlConn.Close()\n\t\treturn fmt.Errorf(\"create kcp connection from udp connection error: %v\", err)\n\t}\n\n\tfmuxCfg := fmux.DefaultConfig()\n\tfmuxCfg.KeepAliveInterval = 10 * time.Second\n\tfmuxCfg.MaxStreamWindowSize = 6 * 1024 * 1024\n\tfmuxCfg.LogOutput = io.Discard\n\tsession, err := fmux.Client(remote, fmuxCfg)\n\tif err != nil {\n\t\tremote.Close()\n\t\treturn fmt.Errorf(\"initial client session error: %v\", err)\n\t}\n\tks.mu.Lock()\n\tks.session = session","sourceCodeStart":324,"sourceCodeEnd":360,"githubUrl":"https://github.com/fatedier/frp/blob/6c8a8d0a97d03b44e9528d30b30c70cb9d61b405/client/visitor/xtcp.go#L324-L360","documentation":"KCPTunnelSession.Init closed the discovery listen socket and failed to DialUDP a new UDP socket bound to the same local address toward the rendezvous address raddr. This is the first step of building the KCP data channel after hole punching; failing here means the OS refused to allocate the UDP socket.","triggerScenarios":"net.DialUDP(\"udp\", laddr, raddr) errors: local port conflict (TIME_WAIT or another socket grabbed it), UDP socket exhaustion (EMFILE), permission issues, or an invalid resolved raddr after the hole-punch exchange.","commonSituations":"File-descriptor limits hit by a busy frpc; the hole-punch local address became invalid because the NAT rebound the mapping; races where the listen conn's local port is reused by another visitor dialing simultaneously.","solutions":["Check file descriptor limits (ulimit -n) and raise them if frpc manages many connections.","Retry the visitor connection; a transient bind conflict usually clears once the old socket is reaped.","If persistent, identify the failing local address (strace/lsof) and confirm the NAT mapping from the nathole exchange is still valid.","Update frpc/frps; xtcp socket lifecycle improves across releases."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Raise ulimit -n on hosts running many visitor connections","Retry visitor dials; bind conflicts are transient","Avoid launching many simultaneous xtcps that race for the same local ports"],"tags":["xtcp","kcp","udp","system-resources"],"backgroundTag":null,"analyzedSha":"6c8a8d0a97d03b44e9528d30b30c70cb9d61b405","analyzedAt":"2026-08-15T06:53:27.215Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}