{"record":{"id":"aefe849f010ba437","repo":"fatedier/frp","slug":"invalid-argument-invalid-proxy-config-type-is-re","errorCode":null,"errorMessage":"invalid argument: invalid proxy config: type is required","messagePattern":"invalid argument: invalid proxy config: type is required","errorType":"http","errorClass":"configmgmt.ErrInvalidArgument","httpStatus":400,"severity":"error","filePath":"client/config_manager.go","lineNumber":205,"sourceCode":"\t\t\t\treturn fmt.Errorf(\"%w: %v\", configmgmt.ErrConflict, err)\n\t\t\t}\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tlog.Infof(\"store: created proxy %q\", name)\n\treturn persisted, nil\n}\n\nfunc (m *serviceConfigManager) UpdateStoreProxy(name string, cfg v1.ProxyConfigurer) (v1.ProxyConfigurer, error) {\n\tif name == \"\" {\n\t\treturn nil, fmt.Errorf(\"%w: proxy name is required\", configmgmt.ErrInvalidArgument)\n\t}\n\tif cfg == nil {\n\t\treturn nil, fmt.Errorf(\"%w: invalid proxy config: type is required\", configmgmt.ErrInvalidArgument)\n\t}\n\tbodyName := cfg.GetBaseConfig().Name\n\tif bodyName != name {\n\t\treturn nil, fmt.Errorf(\"%w: proxy name in URL must match name in body\", configmgmt.ErrInvalidArgument)\n\t}\n\tif err := m.validateStoreProxyConfigurer(cfg); err != nil {\n\t\treturn nil, fmt.Errorf(\"%w: validation error: %v\", configmgmt.ErrInvalidArgument, err)\n\t}\n\n\tpersisted, err := m.withStoreProxyMutationAndReload(name, func(storeSource *source.StoreSource) error {\n\t\tif err := storeSource.UpdateProxy(cfg); err != nil {\n\t\t\tif errors.Is(err, source.ErrNotFound) {\n\t\t\t\treturn fmt.Errorf(\"%w: %v\", configmgmt.ErrNotFound, err)\n\t\t\t}\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})","sourceCodeStart":187,"sourceCodeEnd":223,"githubUrl":"https://github.com/fatedier/frp/blob/6c8a8d0a97d03b44e9528d30b30c70cb9d61b405/client/config_manager.go#L187-L223","documentation":"Returned by UpdateStoreProxy when the decoded request body produced a nil ProxyConfigurer. In practice the frpc controller decodes the body's type discriminator into a concrete configurer; a body without a recognized 'type' (or a totally unparseable body) yields nil, which this guard rejects as 'type is required' with ErrInvalidArgument.","triggerScenarios":"PUT /api/store/proxies/{name} with a body missing the \"type\" field, with an unsupported type string, or with an empty body; sending form-encoded or YAML data to a JSON endpoint so decoding yields nothing.","commonSituations":"Copy-pasting a proxy definition from docs that omit type; typos like \"TCP\" (case-sensitive) or \"tcpv2\"; sending the body as query parameters instead of JSON.","solutions":["Include a valid \"type\" field in the JSON body (tcp, udp, http, https, tcpmux, stcp, sudp, xtcp — lowercase).","Confirm the Content-Type and that the body is JSON, matching what GET /api/store/proxies/{name} returns.","Round-trip: GET the current proxy, modify fields, PUT the whole object back."],"exampleFix":"# before\ncurl -X PUT http://127.0.0.1:7400/api/store/proxies/ssh -d '{\"name\":\"ssh\",\"localPort\":22,\"remotePort\":6022}'\n# 400 invalid proxy config: type is required\n\n# after\ncurl -X PUT http://127.0.0.1:7400/api/store/proxies/ssh -d '{\"type\":\"tcp\",\"name\":\"ssh\",\"localPort\":22,\"remotePort\":6022}'","handlingStrategy":"validation","validationCode":"// Require a known proxy type before PUT.\nvalidTypes := map[string]bool{\"tcp\":true,\"udp\":true,\"http\":true,\"https\":true,\"tcpmux\":true,\"stcp\":true,\"sudp\":true,\"xtcp\":true}\nif !validTypes[body.Type] {\n    return fmt.Errorf(\"missing or unsupported proxy type %q\", body.Type)\n}","typeGuard":null,"tryCatchPattern":"if _, err := mgr.UpdateStoreProxy(name, cfg); err != nil {\n    if errors.Is(err, configmgmt.ErrInvalidArgument) && strings.Contains(err.Error(), \"type is required\") {\n        // body decoding produced no configurer: fix type field / content-type\n    }\n}","preventionTips":["Always include lowercase \"type\" in proxy bodies","Send Content-Type: application/json matching GET responses"],"tags":["frp","frpc","store","proxy","validation","json"],"backgroundTag":null,"analyzedSha":"6c8a8d0a97d03b44e9528d30b30c70cb9d61b405","analyzedAt":"2026-08-15T06:53:27.215Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}