{"record":{"id":"637e928f2dd1a4de","repo":"fatedier/frp","slug":"proxy-name-in-url-must-match-name-in-body","errorCode":null,"errorMessage":"proxy name in URL must match name in body","messagePattern":"proxy name in URL must match name in body","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"error","filePath":"client/http/model/proxy_definition.go","lineNumber":32,"sourceCode":"\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\nfunc (p *ProxyDefinition) ToConfigurer() (v1.ProxyConfigurer, error) {\n\tblock, _, _ := p.activeBlock()\n\tif block == nil {\n\t\treturn nil, fmt.Errorf(\"exactly one proxy type block is required\")\n\t}\n","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/fatedier/frp/blob/6c8a8d0a97d03b44e9528d30b30c70cb9d61b405/client/http/model/proxy_definition.go#L14-L50","documentation":"Returned by ProxyDefinition.Validate during an update (PUT /api/proxies/{name}) when the name in the URL path differs from the \"name\" field in the JSON body. frpc refuses to rename a proxy via update because the name is its identity key; both must agree.","triggerScenarios":"PUT /api/proxies/old-name with body {\"name\": \"new-name\", ...}; also triggers when pathName is provided and body name is a different non-empty string. It only applies when isUpdate is true (updates), not creates.","commonSituations":"Client code templating the body with a new name while keeping the old URL; attempting to rename a proxy with PUT instead of delete+create; stale cached body from a previous proxy being reused for a different one.","solutions":["Make the body's \"name\" identical to the name in the URL path.","To rename a proxy, DELETE the old one and POST a new definition — updates cannot change identity.","Add an assertion in client code that body.name == URL name before sending the PUT."],"exampleFix":"// before\nPUT /api/proxies/ssh-old\n{\"name\": \"ssh-new\", \"type\": \"tcp\", ...}\n\n// after\nPUT /api/proxies/ssh-old\n{\"name\": \"ssh-old\", \"type\": \"tcp\", ...}","handlingStrategy":"validation","validationCode":"func checkNameMatch(pathName string, body map[string]any) error {\n    name, _ := body[\"name\"].(string)\n    if pathName != \"\" && name != pathName { return fmt.Errorf(\"body name %q != URL name %q\", name, pathName) }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Single-source the name: build both URL and body from one variable.","Never attempt renames via PUT; implement rename as delete + create.","Add a pre-send assertion name == pathName in API client wrappers."],"tags":["api","validation","update","frpc-admin"],"backgroundTag":null,"analyzedSha":"6c8a8d0a97d03b44e9528d30b30c70cb9d61b405","analyzedAt":"2026-08-15T06:53:27.215Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}