{"record":{"id":"e08d6160be44ad59","repo":"fatedier/frp","slug":"invalid-protocol","errorCode":null,"errorMessage":"invalid protocol","messagePattern":"invalid protocol","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/config/legacy/client.go","lineNumber":384,"sourceCode":"\t\t}\n\t}\n\n\tif !cfg.TLSEnable {\n\t\tif cfg.TLSCertFile != \"\" {\n\t\t\tfmt.Println(\"WARNING! tls_cert_file is invalid when tls_enable is false\")\n\t\t}\n\n\t\tif cfg.TLSKeyFile != \"\" {\n\t\t\tfmt.Println(\"WARNING! tls_key_file is invalid when tls_enable is false\")\n\t\t}\n\n\t\tif cfg.TLSTrustedCaFile != \"\" {\n\t\t\tfmt.Println(\"WARNING! tls_trusted_ca_file is invalid when tls_enable is false\")\n\t\t}\n\t}\n\n\tif !slices.Contains([]string{\"tcp\", \"kcp\", \"quic\", \"websocket\", \"wss\"}, cfg.Protocol) {\n\t\treturn fmt.Errorf(\"invalid protocol\")\n\t}\n\n\tfor _, f := range cfg.IncludeConfigFiles {\n\t\tabsDir, err := filepath.Abs(filepath.Dir(f))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"include: parse directory of %s failed: %v\", f, err)\n\t\t}\n\t\tif _, err := os.Stat(absDir); os.IsNotExist(err) {\n\t\t\treturn fmt.Errorf(\"include: directory of %s not exist\", f)\n\t\t}\n\t}\n\treturn nil\n}\n","sourceCodeStart":366,"sourceCodeEnd":398,"githubUrl":"https://github.com/fatedier/frp/blob/6c8a8d0a97d03b44e9528d30b30c70cb9d61b405/pkg/config/legacy/client.go#L366-L398","documentation":"ClientCommonConf.Validate in the legacy INI client config rejects any protocol value outside the allowlist tcp, kcp, quic, websocket, wss. The protocol field selects the transport frpc uses to connect to frps, so unknown values cannot be mapped to a dialer.","triggerScenarios":"A legacy frpc.ini with protocol = http, protocol = grpc, a typo like protocal/websockt, or trailing whitespace/case differences (the check is case-sensitive, only lowercase matches pass).","commonSituations":"Copy-paste from nginx/other proxy docs where 'http' is a valid protocol; upgrading frp and assuming newly discussed transports exist in the installed version; kcp/quic builds where the string was misspelled.","solutions":["Change protocol to one of: tcp, kcp, quic websocket, wss (exactly lowercase)","Check for typos and surrounding quotes/whitespace in the INI value","Verify the matching server side has the transport enabled (e.g. quic/websocket ports on frps) after fixing the value"],"exampleFix":"# before\n[common]\nprotocol = http\n\n# after\n[common]\nprotocol = websocket","handlingStrategy":"validation","validationCode":"var allowedProtocols = map[string]bool{\"tcp\":true,\"kcp\":true,\"quic\":true,\"websocket\":true,\"wss\":true}\nif !allowedProtocols[common.Protocol] {\n    return fmt.Errorf(\"protocol %q not supported; use tcp/kcp/quic/websocket/wss\", common.Protocol)\n}","typeGuard":"func isSupportedProtocol(p string) bool {\n    switch p {\n    case \"tcp\", \"kcp\", \"quic\", \"websocket\", \"wss\":\n        return true\n    }\n    return false\n}","tryCatchPattern":"if err := cfg.Validate(); err != nil { if strings.HasPrefix(err.Error(), \"invalid protocol\") { /* surface allowlist to the user */ } return err }","preventionTips":["Keep the protocol allowlist next to your config templates","Lint INI values for lowercase exact matches","Document supported transports per frp version in your runbook"],"tags":["config","validation","protocol","legacy-ini","frpc"],"backgroundTag":null,"analyzedSha":"6c8a8d0a97d03b44e9528d30b30c70cb9d61b405","analyzedAt":"2026-08-15T06:53:27.215Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}