fatedier/frp · error · configmgmt.ErrNotFound
not found: %v
Error message
not found: %v
What it means
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.
Source
Thrown at client/config_manager.go:218
func (m *serviceConfigManager) UpdateStoreProxy(name string, cfg v1.ProxyConfigurer) (v1.ProxyConfigurer, error) {
if name == "" {
return nil, fmt.Errorf("%w: proxy name is required", configmgmt.ErrInvalidArgument)
}
if cfg == nil {
return nil, fmt.Errorf("%w: invalid proxy config: type is required", configmgmt.ErrInvalidArgument)
}
bodyName := cfg.GetBaseConfig().Name
if bodyName != name {
return nil, fmt.Errorf("%w: proxy name in URL must match name in body", configmgmt.ErrInvalidArgument)
}
if err := m.validateStoreProxyConfigurer(cfg); err != nil {
return nil, fmt.Errorf("%w: validation error: %v", configmgmt.ErrInvalidArgument, err)
}
persisted, err := m.withStoreProxyMutationAndReload(name, func(storeSource *source.StoreSource) error {
if err := storeSource.UpdateProxy(cfg); err != nil {
if errors.Is(err, source.ErrNotFound) {
return fmt.Errorf("%w: %v", configmgmt.ErrNotFound, err)
}
return err
}
return nil
})
if err != nil {
return nil, err
}
log.Infof("store: updated proxy %q", name)
return persisted, nil
}
func (m *serviceConfigManager) DeleteStoreProxy(name string) error {
if name == "" {
return fmt.Errorf("%w: proxy name is required", configmgmt.ErrInvalidArgument)
}
View on GitHub (pinned to 6c8a8d0a97)
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.
Example fix
# before
curl -X PUT http://127.0.0.1:7400/api/store/proxies/web -d '{"type":"http","name":"web",...}'
# 404 not found: proxy web
# after
curl -X POST http://127.0.0.1:7400/api/store/proxies -d '{"type":"http","name":"web",...}'
curl -X PUT http://127.0.0.1:7400/api/store/proxies/web -d '{"type":"http","name":"web",...}' Defensive patterns
Strategy: try-catch
Validate before calling
// Decide create vs update before acting.
if _, err := mgr.GetStoreProxy(name); errors.Is(err, configmgmt.ErrNotFound) {
_, err = mgr.CreateStoreProxy(cfg) // create when absent
} else {
_, err = mgr.UpdateStoreProxy(name, cfg)
} Try / catch
if _, err := mgr.UpdateStoreProxy(name, cfg); err != nil {
if errors.Is(err, configmgmt.ErrNotFound) {
// PUT is not upsert: fall back to CreateStoreProxy
}
} Prevention
- Do not assume PUT is upsert; decide explicitly
- Sync store contents after intentional deletions so tooling state matches
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- not found: proxy %q
- invalid argument: proxy name is required
- invalid argument: validation error: %v
- conflict: %v
- invalid argument: invalid proxy config: type is required
AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15).
Data as JSON: /api/errors/1d013738f5ecbee3.
Report an issue: GitHub.