{"record":{"id":"5072050f48a4d1f6","repo":"fatedier/frp","slug":"local-port-and-remote-port-is-necessary","errorCode":null,"errorMessage":"local_port and remote_port is necessary","messagePattern":"local_port and remote_port is necessary","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/config/legacy/client.go","lineNumber":312,"sourceCode":"\t\treturn fmt.Errorf(\"local_port or remote_port is empty\")\n\t}\n\n\tlocalPorts, err := util.ParseRangeNumbers(localPortStr)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tremotePorts, err := util.ParseRangeNumbers(remotePortStr)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif len(localPorts) != len(remotePorts) {\n\t\treturn fmt.Errorf(\"local ports number should be same with remote ports number\")\n\t}\n\n\tif len(localPorts) == 0 {\n\t\treturn fmt.Errorf(\"local_port and remote_port is necessary\")\n\t}\n\n\t// Templates\n\tprefix := strings.TrimSpace(strings.TrimPrefix(section.Name(), \"range:\"))\n\n\tfor i := range localPorts {\n\t\ttmpname := fmt.Sprintf(\"%s_%d\", prefix, i)\n\n\t\ttmpsection, err := f.NewSection(tmpname)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tcopySection(section, tmpsection)\n\t\tif _, err := tmpsection.NewKey(\"local_port\", fmt.Sprintf(\"%d\", localPorts[i])); err != nil {\n\t\t\treturn fmt.Errorf(\"local_port new key in section error: %v\", err)\n\t\t}\n\t\tif _, err := tmpsection.NewKey(\"remote_port\", fmt.Sprintf(\"%d\", remotePorts[i])); err != nil {","sourceCodeStart":294,"sourceCodeEnd":330,"githubUrl":"https://github.com/fatedier/frp/blob/6c8a8d0a97d03b44e9528d30b30c70cb9d61b405/pkg/config/legacy/client.go#L294-L330","documentation":"Defensive check after range expansion: the local port list must contain at least one entry. In practice it is nearly unreachable — util.ParseRangeNumbers returns an error for empty or non-numeric strings before this point, and the empty-string case is already rejected by the earlier 'local_port or remote_port is empty' check. It guards against future parser changes that could yield zero ports from a non-empty input.","triggerScenarios":"Only conceivable if ParseRangeNumbers succeeded but produced an empty list — which its current implementation cannot do (any non-empty input either parses to >=1 number or errors). Expect to never see this error from real config files.","commonSituations":"None in practice; if it ever appears, suspect a modified/patched ParseRangeNumbers or a corrupted frp build.","solutions":["Treat occurrence as a bug: report it upstream with the config values for local_port/remote_port","Ensure both keys hold at least one valid port number as with errors 155/156"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat occurrence as a bug in the parser; report upstream with config content","Keep range values non-empty and numeric so earlier validations govern"],"tags":["frp","config","ini","range-proxy","defensive-code"],"backgroundTag":null,"analyzedSha":"6c8a8d0a97d03b44e9528d30b30c70cb9d61b405","analyzedAt":"2026-08-15T06:53:27.215Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}