{"record":{"id":"a201d3bb6263d4f5","repo":"fatedier/frp","slug":"unsupported-udp-packet-codec-selection-s","errorCode":null,"errorMessage":"unsupported UDP packet codec selection: %s","messagePattern":"unsupported UDP packet codec selection: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/service.go","lineNumber":781,"sourceCode":"\t\t}(context.Background(), c)\n\t}\n}\n\nfunc (svr *Service) RegisterControl(\n\tctlConn *msg.Conn,\n\tloginMsg *msg.Login,\n\tinternal bool,\n\twireProtocol string,\n\tudpPacketCodec string,\n) (*Control, error) {\n\tswitch wireProtocol {\n\tcase wire.ProtocolV1:\n\t\tif udpPacketCodec != \"\" {\n\t\t\treturn nil, fmt.Errorf(\"UDP packet codec %q requires wire protocol v2\", udpPacketCodec)\n\t\t}\n\tcase wire.ProtocolV2:\n\t\tif udpPacketCodec != \"\" && udpPacketCodec != wire.UDPPacketCodecBinary {\n\t\t\treturn nil, fmt.Errorf(\"unsupported UDP packet codec selection: %s\", udpPacketCodec)\n\t\t}\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unsupported wire protocol: %s\", wireProtocol)\n\t}\n\t// If client's RunID is empty, it's a new client, we just create a new controller.\n\t// Otherwise, we check if there is one controller has the same run id. If so, we release previous controller and start new one.\n\tvar err error\n\tif loginMsg.RunID == \"\" {\n\t\tloginMsg.RunID, err = util.RandID()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tif err := validation.ValidateRunID(loginMsg.RunID); err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid run id: %w\", err)\n\t}\n\n\tctx := netpkg.NewContextFromConn(ctlConn)","sourceCodeStart":763,"sourceCodeEnd":799,"githubUrl":"https://github.com/fatedier/frp/blob/6c8a8d0a97d03b44e9528d30b30c70cb9d61b405/server/service.go#L763-L799","documentation":"With wire protocol v2, RegisterControl only accepts udpPacketCodec values that are empty or equal to the built-in binary codec; anything else is rejected as an unsupported selection. This guards against clients requesting codec names the server cannot negotiate.","triggerScenarios":"udpPacketCodec set to a misspelled or not-yet-implemented value (e.g. \"binary \" with whitespace, \"protobuf\", \"text\") while on v2; configs from a future/other fork referencing codecs this server lacks.","commonSituations":"Typos in the codec name; version skew where the client knows a codec the server does not; hand-ported configs.","solutions":["Set udpPacketCodec = \"binary\" (the only supported value) or leave it empty","Check for whitespace/case errors in the value","Upgrade frps if a newer codec name is genuinely required by your frpc"],"exampleFix":"# before\nudpPacketCodec = \"protobuf\"\n\n# after\nudpPacketCodec = \"binary\"","handlingStrategy":"validation","validationCode":"if cfg.UDPPacketCodec != \"\" && cfg.UDPPacketCodec != \"binary\" {\n    return fmt.Errorf(\"udpPacketCodec must be empty or 'binary', got %q\", cfg.UDPPacketCodec)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Restrict the codec field to the documented enum at config-parse time","Trim whitespace and normalize case when loading config files","Re-check supported codec names after upgrading frps"],"tags":["frpc","config","udp","wire-protocol","validation"],"backgroundTag":null,"analyzedSha":"6c8a8d0a97d03b44e9528d30b30c70cb9d61b405","analyzedAt":"2026-08-15T06:53:27.215Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}