{"record":{"id":"2f8c839a08d58850","repo":"fatedier/frp","slug":"local-port-or-remote-port-is-empty","errorCode":null,"errorMessage":"local_port or remote_port is empty","messagePattern":"local_port or remote_port is empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/config/legacy/client.go","lineNumber":294,"sourceCode":"\t\tcase \"visitor\":\n\t\t\tnewConf, newErr := NewVisitorConfFromIni(prefix, name, section)\n\t\t\tif newErr != nil {\n\t\t\t\treturn nil, nil, fmt.Errorf(\"failed to parse visitor %s, err: %v\", name, newErr)\n\t\t\t}\n\t\t\tvisitorConfs[prefix+name] = newConf\n\t\tdefault:\n\t\t\treturn nil, nil, fmt.Errorf(\"proxy %s role should be 'server' or 'visitor'\", name)\n\t\t}\n\t}\n\treturn proxyConfs, visitorConfs, nil\n}\n\nfunc renderRangeProxyTemplates(f *ini.File, section *ini.Section) error {\n\t// Validation\n\tlocalPortStr := section.Key(\"local_port\").String()\n\tremotePortStr := section.Key(\"remote_port\").String()\n\tif localPortStr == \"\" || remotePortStr == \"\" {\n\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\")","sourceCodeStart":276,"sourceCodeEnd":312,"githubUrl":"https://github.com/fatedier/frp/blob/6c8a8d0a97d03b44e9528d30b30c70cb9d61b405/pkg/config/legacy/client.go#L276-L312","documentation":"First validation inside renderRangeProxyTemplates for [range:...] sections: the string values of local_port and remote_port must both be non-empty before range expansion. An empty (or absent) key aborts with this error, which then surfaces wrapped as 'failed to render template for proxy range:...' (error 151).","triggerScenarios":"A [range:...] section that defines only local_port, only remote_port, or neither; a key commented out or mistyped (e.g. localport without the underscore) so it reads as empty.","commonSituations":"Creating a range section by copying a normal proxy section that had a default remote_port behavior; typos in key names; commenting out one port while testing.","solutions":["Add both local_port and remote_port keys with valid values or ranges to the [range:...] section","Use the exact underscore-separated key names","Remember ranges are mandatory in range sections even if a single proxy of the same type could omit them"],"exampleFix":"; before\n[range:ssh]\ntype = tcp\nlocal_port = 6000,6001\n; remote_port missing\n\n; after\n[range:ssh]\ntype = tcp\nlocal_port = 6000,6001\nremote_port = 7000,7001","handlingStrategy":"validation","validationCode":"if strings.TrimSpace(section.Key(\"local_port\").String()) == \"\" ||\n   strings.TrimSpace(section.Key(\"remote_port\").String()) == \"\" {\n    return fmt.Errorf(\"%s: local_port and remote_port are required in range sections\", section.Name())\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Copy a known-good range section as the starting point","Use exact key names local_port / remote_port","Run the config through frpc verify after editing"],"tags":["frp","config","ini","range-proxy","validation"],"backgroundTag":null,"analyzedSha":"6c8a8d0a97d03b44e9528d30b30c70cb9d61b405","analyzedAt":"2026-08-15T06:53:27.215Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}