{"record":{"id":"f0f675cd12cabb3b","repo":"fatedier/frp","slug":"type-shouldn-t-be-empty","errorCode":null,"errorMessage":"type shouldn't be empty","messagePattern":"type shouldn't be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/config/legacy/visitor.go","lineNumber":173,"sourceCode":"\tif cfg.MaxRetriesAnHour <= 0 {\n\t\tcfg.MaxRetriesAnHour = 8\n\t}\n\tif cfg.MinRetryInterval <= 0 {\n\t\tcfg.MinRetryInterval = 90\n\t}\n\tif cfg.FallbackTimeoutMs <= 0 {\n\t\tcfg.FallbackTimeoutMs = 1000\n\t}\n\treturn\n}\n\n// Visitor loaded from ini\nfunc NewVisitorConfFromIni(prefix string, name string, section *ini.Section) (VisitorConf, error) {\n\t// section.Key: if key not exists, section will set it with default value.\n\tvisitorType := VisitorType(section.Key(\"type\").String())\n\n\tif visitorType == \"\" {\n\t\treturn nil, fmt.Errorf(\"type shouldn't be empty\")\n\t}\n\n\tconf := DefaultVisitorConf(visitorType)\n\tif conf == nil {\n\t\treturn nil, fmt.Errorf(\"type [%s] error\", visitorType)\n\t}\n\n\tif err := conf.UnmarshalFromIni(prefix, name, section); err != nil {\n\t\treturn nil, fmt.Errorf(\"type [%s] error\", visitorType)\n\t}\n\treturn conf, nil\n}\n","sourceCodeStart":155,"sourceCodeEnd":186,"githubUrl":"https://github.com/fatedier/frp/blob/6c8a8d0a97d03b44e9528d30b30c70cb9d61b405/pkg/config/legacy/visitor.go#L155-L186","documentation":"NewVisitorConfFromIni reads the type key of a visitor INI section; unlike proxies, visitors have no default. If type is empty the config is rejected immediately with 'type shouldn't be empty'. Visitors must explicitly declare stcp, sudp, or xtcp.","triggerScenarios":"A [visitor.x] or similarly named section in legacy frpc.ini where the type key is missing or blank. Merely having a section named like a visitor without a type triggers it during LoadAllProxyConfsFromIni.","commonSituations":"Users adding a visitor section by copying a proxy section and deleting fields; forgetting that visitors require type while proxies silently default to tcp.","solutions":["Add type = stcp (or sudp/xtcp) to the visitor section","If the section was not meant to be a visitor, rename it so it is not detected as one (check the naming convention used to detect visitor sections)","Validate with frpc verify -c frpc.ini"],"exampleFix":"# before\n[secret-visitor]\nname = sv\nserver_name = secret\n\n# after\n[secret-visitor]\ntype = stcp\nname = sv\nserver_name = secret","handlingStrategy":"validation","validationCode":"if section.Key(\"type\").String() == \"\" {\n    return fmt.Errorf(\"visitor section [%s] missing type (stcp/sudp/xtcp)\", section.Name())\n}","typeGuard":"func hasVisitorType(s *ini.Section) bool { return s.Key(\"type\").String() != \"\" }","tryCatchPattern":"if _, err := legacy.NewVisitorConfFromIni(prefix, name, section); err != nil && err.Error() == \"type shouldn't be empty\" { /* add type key */ }","preventionTips":["Never copy a proxy section into a visitor section without rewriting fields","Require explicit type in visitor snippets","frpc verify before deploy"],"tags":["config","visitor","validation","legacy-ini","frpc"],"backgroundTag":null,"analyzedSha":"6c8a8d0a97d03b44e9528d30b30c70cb9d61b405","analyzedAt":"2026-08-15T06:53:27.215Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}