{"record":{"id":"f69f683b3c859af0","repo":"fatedier/frp","slug":"listen-on-quic-udp-address-s-error-v","errorCode":null,"errorMessage":"listen on quic udp address %s error: %v","messagePattern":"listen on quic udp address (.+?) error: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"server/service.go","lineNumber":275,"sourceCode":"\t\taddress := net.JoinHostPort(cfg.BindAddr, strconv.Itoa(cfg.KCPBindPort))\n\t\tsvr.kcpListener, err = netpkg.ListenKcp(address)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"listen on kcp udp address %s error: %v\", address, err)\n\t\t}\n\t\tlog.Infof(\"frps kcp listen on udp %s\", address)\n\t}\n\n\tif cfg.QUICBindPort > 0 {\n\t\taddress := net.JoinHostPort(cfg.BindAddr, strconv.Itoa(cfg.QUICBindPort))\n\t\tquicTLSCfg := tlsConfig.Clone()\n\t\tquicTLSCfg.NextProtos = []string{\"frp\"}\n\t\tsvr.quicListener, err = quic.ListenAddr(address, quicTLSCfg, &quic.Config{\n\t\t\tMaxIdleTimeout:     time.Duration(cfg.Transport.QUIC.MaxIdleTimeout) * time.Second,\n\t\t\tMaxIncomingStreams: int64(cfg.Transport.QUIC.MaxIncomingStreams),\n\t\t\tKeepAlivePeriod:    time.Duration(cfg.Transport.QUIC.KeepalivePeriod) * time.Second,\n\t\t})\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"listen on quic udp address %s error: %v\", address, err)\n\t\t}\n\t\tlog.Infof(\"frps quic listen on %s\", address)\n\t}\n\n\tif cfg.SSHTunnelGateway.BindPort > 0 {\n\t\tsshGateway, err := ssh.NewGateway(cfg.SSHTunnelGateway, cfg.BindAddr, svr.sshTunnelListener)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"create ssh gateway error: %v\", err)\n\t\t}\n\t\tsvr.sshTunnelGateway = sshGateway\n\t\tlog.Infof(\"frps sshTunnelGateway listen on port %d\", cfg.SSHTunnelGateway.BindPort)\n\t}\n\n\t// Listen for accepting connections from client using websocket protocol.\n\twebsocketPrefix := []byte(\"GET \" + netpkg.FrpWebsocketPath)\n\twebsocketLn := svr.muxer.Listen(0, uint32(len(websocketPrefix)), func(data []byte) bool {\n\t\treturn bytes.Equal(data, websocketPrefix)\n\t})","sourceCodeStart":257,"sourceCodeEnd":293,"githubUrl":"https://github.com/fatedier/frp/blob/6c8a8d0a97d03b44e9528d30b30c70cb9d61b405/server/service.go#L257-L293","documentation":"When QUICBindPort > 0, frps calls quic.ListenAddr on BindAddr:QUICBindPort with the server TLS config. Any failure (bind error, TLS misconfiguration) aborts service creation with the address echoed in the error.","triggerScenarios":"QUIC UDP port already in use; TLS certificate/key invalid so the cloned tlsConfig cannot back a QUIC listener; BindAddr not present on the host.","commonSituations":"Running QUIC on a port already used by another QUIC/HTTP3 service; self-signed or unreadable cert files; UDP blocked by cloud security groups.","solutions":["Free or change quicBindPort","Validate the TLS cert/key pair configured on frps (they must parse and match)","Confirm UDP egress/ingress is permitted if behind NAT/firewalls","Disable quicBindPort if QUIC transport is not needed"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Validate TLS material and UDP port before enabling QUIC.\nif _, err := tls.LoadX509KeyPair(cfg.TLSCertFile, cfg.TLSKeyFile); err != nil {\n    return err\n}\nif c, err := net.ListenPacket(\"udp\", addr); err != nil { return err } else { c.Close() }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Health-check cert/key pairs in config validation, not at boot","Confirm cloud security groups allow the QUIC UDP port in both directions","Disable quicBindPort in environments where UDP is filtered"],"tags":["frps","startup","quic","udp","tls","port"],"backgroundTag":null,"analyzedSha":"6c8a8d0a97d03b44e9528d30b30c70cb9d61b405","analyzedAt":"2026-08-15T06:53:27.215Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}