{"record":{"id":"26d0abb29da49772","repo":"fatedier/frp","slug":"conflict-v","errorCode":null,"errorMessage":"conflict: %v","messagePattern":"conflict: (.+?)","errorType":"http","errorClass":"configmgmt.ErrConflict","httpStatus":409,"severity":"error","filePath":"client/config_manager.go","lineNumber":187,"sourceCode":"\t}\n\n\tcfg := storeSource.GetProxy(name)\n\tif cfg == nil {\n\t\treturn nil, fmt.Errorf(\"%w: proxy %q\", configmgmt.ErrNotFound, name)\n\t}\n\treturn cfg, nil\n}\n\nfunc (m *serviceConfigManager) CreateStoreProxy(cfg v1.ProxyConfigurer) (v1.ProxyConfigurer, error) {\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\tname := cfg.GetBaseConfig().Name\n\tpersisted, err := m.withStoreProxyMutationAndReload(name, func(storeSource *source.StoreSource) error {\n\t\tif err := storeSource.AddProxy(cfg); err != nil {\n\t\t\tif errors.Is(err, source.ErrAlreadyExists) {\n\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)","sourceCodeStart":169,"sourceCodeEnd":205,"githubUrl":"https://github.com/fatedier/frp/blob/6c8a8d0a97d03b44e9528d30b30c70cb9d61b405/client/config_manager.go#L169-L205","documentation":"Returned by CreateStoreProxy when storeSource.AddProxy reports source.ErrAlreadyExists, meaning a proxy with the same name is already persisted in the store. Wrapped with configmgmt.ErrConflict and surfaced as HTTP 409. Creation is rejected without touching the existing entry.","triggerScenarios":"POST /api/store/proxies with a name that already exists in the store; re-running an idempotent provisioning script that always POSTs the same proxy; racing two concurrent creates of the same name.","commonSituations":"Infrastructure tooling (Terraform/Ansible) re-applying the same proxy definition; retry of a request whose response was lost, so the first attempt actually succeeded; migrating a file-defined proxy to the store without deleting the original.","solutions":["If you mean to replace it, use PUT /api/store/proxies/{name} (UpdateStoreProxy) instead of POST.","If the duplicate is accidental, pick a different name or delete the existing one with DELETE /api/store/proxies/{name} first.","Make provisioning scripts check GET /api/store/proxies/{name} (expect 404) before POSTing, or treat 409 as 'already done'."],"exampleFix":"# before\ncurl -X POST http://127.0.0.1:7400/api/store/proxies -d '{\"type\":\"tcp\",\"name\":\"ssh\",\"localPort\":22,\"remotePort\":6022}'\n# 409 conflict: proxy ssh already exists\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":"try-catch","validationCode":"// Optional pre-check: only POST when GET returns 404.\nif _, err := mgr.GetStoreProxy(name); err == nil {\n    // exists -> update instead\n}","typeGuard":null,"tryCatchPattern":"if _, err := mgr.CreateStoreProxy(cfg); err != nil {\n    if errors.Is(err, configmgmt.ErrConflict) {\n        // already provisioned: switch to UpdateStoreProxy or treat as done\n    }\n}","preventionTips":["Make provisioning idempotent: POST on 404, PUT otherwise","Treat 409 as success in re-runnable scripts"],"tags":["frp","frpc","store","proxy","conflict","idempotency"],"backgroundTag":null,"analyzedSha":"6c8a8d0a97d03b44e9528d30b30c70cb9d61b405","analyzedAt":"2026-08-15T06:53:27.215Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}