{"record":{"id":"6b2abd9776e7ffac","repo":"fatedier/frp","slug":"failed-to-parse-visitor-s-err-v","errorCode":null,"errorMessage":"failed to parse visitor %s, err: %v","messagePattern":"failed to parse visitor (.+?), err: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/config/legacy/client.go","lineNumber":279,"sourceCode":"\t\t\tcontinue\n\t\t}\n\n\t\troleType := section.Key(\"role\").String()\n\t\tif roleType == \"\" {\n\t\t\troleType = \"server\"\n\t\t}\n\n\t\tswitch roleType {\n\t\tcase \"server\":\n\t\t\tnewConf, newErr := NewProxyConfFromIni(prefix, name, section)\n\t\t\tif newErr != nil {\n\t\t\t\treturn nil, nil, fmt.Errorf(\"failed to parse proxy %s, err: %v\", name, newErr)\n\t\t\t}\n\t\t\tproxyConfs[prefix+name] = newConf\n\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)","sourceCodeStart":261,"sourceCodeEnd":297,"githubUrl":"https://github.com/fatedier/frp/blob/6c8a8d0a97d03b44e9528d30b30c70cb9d61b405/pkg/config/legacy/client.go#L261-L297","documentation":"Legacy ini loader counterpart of error 152: for a section with role = 'visitor', NewVisitorConfFromIni maps and validates it. Failures — missing required visitor fields (server_name, bind_port, secret_key for stcp/xtcp/sudp visitors), invalid ports, wrong type for a visitor — are wrapped with the section name.","triggerScenarios":"A [role = visitor] section for an stcp/xtcp/sudp proxy that omits server_name or secret_key, sets a non-numeric bind_port, or uses a type that does not support visitors (http/https/tcpmux).","commonSituations":"Setting up an stcp visitor and copying the server-side section without renaming keys; forgetting that visitors reference the exposing proxy by server_name, not proxy name; bind_port conflicts noted as invalid values.","solutions":["Read the inner error to see which required key failed","For stcp/xtcp visitors set: type, server_name (the exposed proxy's name), secret_key, bind_port, and role = visitor","Ensure bind_port is a valid integer on the visitor host","Confirm the exposing side and visitor share the same secret_key and server_name"],"exampleFix":"; before\n[secret_visor]\nrole = visitor\ntype = stcp\nserver_name = secret-http\nbind_port = 8080\n; missing secret_key\n\n; after\n[secret_visor]\nrole = visitor\ntype = stcp\nserver_name = secret-http\nsecret_key = \"abcdef\"\nbind_port = 8080","handlingStrategy":"validation","validationCode":"required := []string{\"server_name\", \"bind_port\"}\nif section.Key(\"type\").String() != \"http\" { /* stcp/xtcp/sudp visitors also need secret_key */ }\nfor _, k := range required {\n    if section.Key(k).String() == \"\" {\n        return fmt.Errorf(\"visitor %s missing %s\", section.Name(), k)\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Template visitor sections with role/type/server_name/secret_key/bind_port pre-filled","Keep secret_key identical on expose and visitor sides","Test visitor configs with frpc verify before rollout"],"tags":["frp","config","ini","visitor","stcp"],"backgroundTag":null,"analyzedSha":"6c8a8d0a97d03b44e9528d30b30c70cb9d61b405","analyzedAt":"2026-08-15T06:53:27.215Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}