{"record":{"id":"1d013738f5ecbee3","repo":"fatedier/frp","slug":"not-found-v","errorCode":null,"errorMessage":"not found: %v","messagePattern":"not found: (.+?)","errorType":"http","errorClass":"configmgmt.ErrNotFound","httpStatus":404,"severity":"error","filePath":"client/config_manager.go","lineNumber":218,"sourceCode":"func (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})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tlog.Infof(\"store: updated proxy %q\", name)\n\treturn persisted, nil\n}\n\nfunc (m *serviceConfigManager) DeleteStoreProxy(name string) error {\n\tif name == \"\" {\n\t\treturn fmt.Errorf(\"%w: proxy name is required\", configmgmt.ErrInvalidArgument)\n\t}\n","sourceCodeStart":200,"sourceCodeEnd":236,"githubUrl":"https://github.com/fatedier/frp/blob/6c8a8d0a97d03b44e9528d30b30c70cb9d61b405/client/config_manager.go#L200-L236","documentation":"Returned by UpdateStoreProxy when storeSource.UpdateProxy reports source.ErrNotFound — no stored proxy carries that name, so there is nothing to update. Wrapped as configmgmt.ErrNotFound (HTTP 404). PUT is not upsert in this API; creation must go through POST.","triggerScenarios":"PUT /api/store/proxies/{name} for a never-created, deleted, or misspelled name; updating a proxy that exists only in the static config file but not in the store source.","commonSituations":"Assuming PUT is upsert; environment drift where the proxy exists in dev store but not prod; a previous DELETE succeeded and tooling did not notice.","solutions":["Create it first with POST /api/store/proxies (full body), then use PUT for subsequent updates.","Verify the exact name via GET /api/store/proxies before updating.","Standardize tooling on 'POST on 404, PUT otherwise' or an explicit create/update decision."],"exampleFix":"# before\ncurl -X PUT http://127.0.0.1:7400/api/store/proxies/web -d '{\"type\":\"http\",\"name\":\"web\",...}'\n# 404 not found: proxy web\n\n# after\ncurl -X POST http://127.0.0.1:7400/api/store/proxies -d '{\"type\":\"http\",\"name\":\"web\",...}'\ncurl -X PUT  http://127.0.0.1:7400/api/store/proxies/web -d '{\"type\":\"http\",\"name\":\"web\",...}'","handlingStrategy":"try-catch","validationCode":"// Decide create vs update before acting.\nif _, err := mgr.GetStoreProxy(name); errors.Is(err, configmgmt.ErrNotFound) {\n    _, err = mgr.CreateStoreProxy(cfg) // create when absent\n} else {\n    _, err = mgr.UpdateStoreProxy(name, cfg)\n}","typeGuard":null,"tryCatchPattern":"if _, err := mgr.UpdateStoreProxy(name, cfg); err != nil {\n    if errors.Is(err, configmgmt.ErrNotFound) {\n        // PUT is not upsert: fall back to CreateStoreProxy\n    }\n}","preventionTips":["Do not assume PUT is upsert; decide explicitly","Sync store contents after intentional deletions so tooling state matches"],"tags":["frp","frpc","store","proxy","not-found"],"backgroundTag":null,"analyzedSha":"6c8a8d0a97d03b44e9528d30b30c70cb9d61b405","analyzedAt":"2026-08-15T06:53:27.215Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}