{"record":{"id":"9a7686301d58931a","repo":"fatedier/frp","slug":"visitor-name-is-required","errorCode":null,"errorMessage":"visitor name is required","messagePattern":"visitor name is required","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"client/http/model/visitor_definition.go","lineNumber":21,"sourceCode":"import (\n\t\"fmt\"\n\t\"strings\"\n\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","sourceCodeStart":3,"sourceCodeEnd":39,"githubUrl":"https://github.com/fatedier/frp/blob/6c8a8d0a97d03b44e9528d30b30c70cb9d61b405/client/http/model/visitor_definition.go#L3-L39","documentation":"Returned by VisitorDefinition.Validate when creating/updating a visitor through frpc's admin API and the JSON body's \"name\" is empty or whitespace-only. Visitors (stcp/sudp/xtcp clients connecting to a peer) are identified by name, so the request is rejected immediately.","triggerScenarios":"POST/PUT /api/visitors with {\"type\":\"stcp\",\"stcp\":{...}} and no top-level \"name\" key, or \"name\": \"  \".","commonSituations":"Client generator omitting the name field; name nested inside the stcp/sudp/xtcp block instead of the top level; whitespace-only name from templating.","solutions":["Add a non-empty top-level \"name\" to the visitor definition body.","Ensure the name is unique among this client's visitors.","Trim and assert the name client-side before sending."],"exampleFix":"// before\n{\"type\": \"stcp\", \"stcp\": {\"serverName\": \"secret\", \"secretKey\": \"k\"}}\n\n// after\n{\"name\": \"secret-visitor\", \"type\": \"stcp\", \"stcp\": {\"serverName\": \"secret\", \"secretKey\": \"k\"}}","handlingStrategy":"validation","validationCode":"func validVisitorName(def map[string]any) error {\n    name, _ := def[\"name\"].(string)\n    if strings.TrimSpace(name) == \"\" { return errors.New(\"visitor name is required\") }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if resp.StatusCode == 400 && strings.Contains(body, \"visitor name is required\") {\n    // regenerate payload with name set and retry once\n}","preventionTips":["Always emit the top-level name for visitor payloads.","Keep visitor names distinct per client.","Validate payload shape in client SDK code before calling the API."],"tags":["api","validation","visitor","frpc-admin"],"backgroundTag":null,"analyzedSha":"6c8a8d0a97d03b44e9528d30b30c70cb9d61b405","analyzedAt":"2026-08-15T06:53:27.215Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}