fatedier/frp · error · configmgmt.ErrInvalidArgument

invalid argument: proxy name in URL must match name in body

Error message

invalid argument: proxy name in URL must match name in body

What it means

Returned by UpdateStoreProxy when the name in the URL path and the name inside the request body differ (bodyName != name). frpc enforces REST consistency so a PUT cannot silently rename an object; rename is delete-then-create. Maps to HTTP 400 via ErrInvalidArgument.

Source

Thrown at client/config_manager.go:209

		return nil
	})
	if err != nil {
		return nil, err
	}
	log.Infof("store: created proxy %q", name)
	return persisted, nil
}

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
	}

View on GitHub (pinned to 6c8a8d0a97)

Solutions

  1. Make the body's name field exactly equal the URL name, or go straight to delete + create with the new name.
  2. In tooling, derive both URL and body name from a single variable.
  3. If renaming is the goal: DELETE /api/store/proxies/old then POST /api/store/proxies with name=new.

Example fix

# before
curl -X PUT http://127.0.0.1:7400/api/store/proxies/ssh \
  -d '{"type":"tcp","name":"ssh-v2","localPort":22,"remotePort":6022}'
# 400 proxy name in URL must match name in body

# after
curl -X PUT http://127.0.0.1:7400/api/store/proxies/ssh \
  -d '{"type":"tcp","name":"ssh","localPort":22,"remotePort":6022}'
Defensive patterns

Strategy: validation

Validate before calling

// Enforce URL/body name equality client-side.
if cfg.GetBaseConfig().Name != name {
    return fmt.Errorf("name mismatch: url=%s body=%s", name, cfg.GetBaseConfig().Name)
}
_, err := mgr.UpdateStoreProxy(name, cfg)

Try / catch

if _, err := mgr.UpdateStoreProxy(name, cfg); err != nil {
    if errors.Is(err, configmgmt.ErrInvalidArgument) && strings.Contains(err.Error(), "must match") {
        // align the two names or do delete+create to rename
    }
}

Prevention

When it happens

Trigger: PUT /api/store/proxies/old-name with a body whose "name" field is "new-name"; automation that updates the body's name field but builds the URL from a stale variable; renaming attempts.

Common situations: Scripts where the URL name comes from CLI args but the body is a rendered template with a different name; editing a fetched config and changing name as a 'label' without realizing it is the identifier.

Related errors


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