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

  1. Create it first with POST /api/store/proxies (full body), then use PUT for subsequent updates.
  2. Verify the exact name via GET /api/store/proxies before updating.
  3. 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

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


AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15). Data as JSON: /api/errors/1d013738f5ecbee3. Report an issue: GitHub.