{"record":{"id":"ed0c5d3acb4c5983","repo":"fatedier/frp","slug":"invalid-visitor-type-s","errorCode":null,"errorMessage":"invalid visitor type: %s","messagePattern":"invalid visitor type: (.+?)","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"client/http/model/visitor_definition.go","lineNumber":24,"sourceCode":"\n\tv1 \"github.com/fatedier/frp/pkg/config/v1\"\n)\n\ntype VisitorDefinition struct {\n\tName string `json:\"name\"`\n\tType string `json:\"type\"`\n\n\tSTCP *v1.STCPVisitorConfig `json:\"stcp,omitempty\"`\n\tSUDP *v1.SUDPVisitorConfig `json:\"sudp,omitempty\"`\n\tXTCP *v1.XTCPVisitorConfig `json:\"xtcp,omitempty\"`\n}\n\nfunc (p *VisitorDefinition) Validate(pathName string, isUpdate bool) error {\n\tif strings.TrimSpace(p.Name) == \"\" {\n\t\treturn fmt.Errorf(\"visitor name is required\")\n\t}\n\tif !IsVisitorType(p.Type) {\n\t\treturn fmt.Errorf(\"invalid visitor type: %s\", p.Type)\n\t}\n\tif isUpdate && pathName != \"\" && pathName != p.Name {\n\t\treturn fmt.Errorf(\"visitor name in URL must match name in body\")\n\t}\n\n\t_, blockType, blockCount := p.activeBlock()\n\tif blockCount != 1 {\n\t\treturn fmt.Errorf(\"exactly one visitor type block is required\")\n\t}\n\tif blockType != p.Type {\n\t\treturn fmt.Errorf(\"visitor type block %q does not match type %q\", blockType, p.Type)\n\t}\n\treturn nil\n}\n\nfunc (p *VisitorDefinition) ToConfigurer() (v1.VisitorConfigurer, error) {\n\tblock, _, _ := p.activeBlock()\n\tif block == nil {","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/fatedier/frp/blob/6c8a8d0a97d03b44e9528d30b30c70cb9d61b405/client/http/model/visitor_definition.go#L6-L42","documentation":"Returned by VisitorDefinition.Validate when the visitor's \"type\" string is not one of the three visitor-capable types: stcp, sudp, xtcp. Other proxy types (tcp, http, ...) cannot be visitors, and any typo or wrong casing fails here.","triggerScenarios":"POST/PUT /api/visitors with \"type\": \"STCP\", \"type\": \"tcp\", \"type\": \"stc\" (typo), or a missing/empty \"type\".","commonSituations":"Assuming every proxy type supports visitors; uppercase type strings; renaming after upgrades; copy-paste from a proxy definition into a visitor payload.","solutions":["Set \"type\" to exactly one of stcp, sudp, xtcp (lowercase).","Check for typos and stray whitespace in the type field.","Remember only p2p/secret types have visitors; for plain tcp/http proxies use a normal proxy, not a visitor."],"exampleFix":"// before\n{\"name\": \"v\", \"type\": \"STCP\", \"stcp\": {...}}\n\n// after\n{\"name\": \"v\", \"type\": \"stcp\", \"stcp\": {...}}","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"func isVisitorType(t string) bool {\n    switch t {\n    case \"stcp\", \"sudp\", \"xtcp\":\n        return true\n    }\n    return false\n}","tryCatchPattern":null,"preventionTips":["Only stcp/sudp/xtcp have visitors — encode this set as a constant in generators.","Lowercase all type strings.","Reject proxy types early in visitor creation flows."],"tags":["api","validation","visitor","frpc-admin"],"backgroundTag":null,"analyzedSha":"6c8a8d0a97d03b44e9528d30b30c70cb9d61b405","analyzedAt":"2026-08-15T06:53:27.215Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}