{"record":{"id":"254f3059c40b4dd8","repo":"fatedier/frp","slug":"proxy-name-is-required","errorCode":null,"errorMessage":"proxy name is required","messagePattern":"proxy name is required","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"error","filePath":"client/http/model/proxy_definition.go","lineNumber":26,"sourceCode":")\n\ntype ProxyDefinition struct {\n\tName string `json:\"name\"`\n\tType string `json:\"type\"`\n\n\tTCP    *v1.TCPProxyConfig    `json:\"tcp,omitempty\"`\n\tUDP    *v1.UDPProxyConfig    `json:\"udp,omitempty\"`\n\tHTTP   *v1.HTTPProxyConfig   `json:\"http,omitempty\"`\n\tHTTPS  *v1.HTTPSProxyConfig  `json:\"https,omitempty\"`\n\tTCPMux *v1.TCPMuxProxyConfig `json:\"tcpmux,omitempty\"`\n\tSTCP   *v1.STCPProxyConfig   `json:\"stcp,omitempty\"`\n\tSUDP   *v1.SUDPProxyConfig   `json:\"sudp,omitempty\"`\n\tXTCP   *v1.XTCPProxyConfig   `json:\"xtcp,omitempty\"`\n}\n\nfunc (p *ProxyDefinition) Validate(pathName string, isUpdate bool) error {\n\tif strings.TrimSpace(p.Name) == \"\" {\n\t\treturn fmt.Errorf(\"proxy name is required\")\n\t}\n\tif !IsProxyType(p.Type) {\n\t\treturn fmt.Errorf(\"invalid proxy type: %s\", p.Type)\n\t}\n\tif isUpdate && pathName != \"\" && pathName != p.Name {\n\t\treturn fmt.Errorf(\"proxy 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 proxy type block is required\")\n\t}\n\tif blockType != p.Type {\n\t\treturn fmt.Errorf(\"proxy type block %q does not match type %q\", blockType, p.Type)\n\t}\n\treturn nil\n}\n","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/fatedier/frp/blob/6c8a8d0a97d03b44e9528d30b30c70cb9d61b405/client/http/model/proxy_definition.go#L8-L44","documentation":"Returned by ProxyDefinition.Validate when creating/updating a proxy through frpc's admin API (POST/PUT /api/proxies) and the JSON body's \"name\" field is empty or whitespace-only. The name is the primary identifier of a proxy, so the request is rejected before any type/block validation runs.","triggerScenarios":"Calling the frpc HTTP API with a proxy definition whose top-level \"name\" is \"\" or missing, e.g. {\"type\":\"tcp\",\"tcp\":{...}} with no \"name\" key, or \"name\": \"   \".","commonSituations":"Client code that builds the JSON dynamically and forgets to set name; YAML/TOML-to-JSON conversion dropping the field; name accidentally placed inside the type block instead of at the top level.","solutions":["Add a non-empty \"name\" at the top level of the proxy definition JSON body.","Trim/verify the name client-side before sending (it must not be only whitespace).","Ensure the name is unique among the client's proxies to avoid later conflicts."],"exampleFix":"// before\nbody := {\"type\": \"tcp\", \"tcp\": {\"localPort\": 22}}\n\n// after\nbody := {\"name\": \"ssh\", \"type\": \"tcp\", \"tcp\": {\"localPort\": 22}}","handlingStrategy":"validation","validationCode":"func validProxyName(def map[string]any) error {\n    name, _ := def[\"name\"].(string)\n    if strings.TrimSpace(name) == \"\" { return errors.New(\"proxy name is required\") }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"resp, err := http.Post(apiURL+\"/api/proxies\", \"application/json\", body)\nif err != nil { return err }\nif resp.StatusCode == 400 {\n    // read body; if \"proxy name is required\", fix payload and retry with name set\n}","preventionTips":["Always set the top-level name field when building proxy definitions programmatically.","Keep names unique and DNS-safe to avoid downstream conflicts.","Run definitions through a local Validate-equivalent before POSTing."],"tags":["api","validation","proxy","frpc-admin"],"backgroundTag":null,"analyzedSha":"6c8a8d0a97d03b44e9528d30b30c70cb9d61b405","analyzedAt":"2026-08-15T06:53:27.215Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}