fatedier/frp · error · configmgmt.ErrInvalidArgument

invalid argument: validation error: %v

Error message

invalid argument: validation error: %v

What it means

Returned by CreateStoreProxy when validateStoreProxyConfigurer rejects the submitted proxy config before anything is persisted. The wrapped validation error details the actual problem (missing/invalid name, missing type, invalid port ranges, invalid plugin fields, etc.). It maps to HTTP 400 via configmgmt.ErrInvalidArgument.

Source

Thrown at client/config_manager.go:180

	if name == "" {
		return nil, fmt.Errorf("%w: proxy name is required", configmgmt.ErrInvalidArgument)
	}

	storeSource, err := m.storeSourceOrError()
	if err != nil {
		return nil, err
	}

	cfg := storeSource.GetProxy(name)
	if cfg == nil {
		return nil, fmt.Errorf("%w: proxy %q", configmgmt.ErrNotFound, name)
	}
	return cfg, nil
}

func (m *serviceConfigManager) CreateStoreProxy(cfg v1.ProxyConfigurer) (v1.ProxyConfigurer, error) {
	if err := m.validateStoreProxyConfigurer(cfg); err != nil {
		return nil, fmt.Errorf("%w: validation error: %v", configmgmt.ErrInvalidArgument, err)
	}

	name := cfg.GetBaseConfig().Name
	persisted, err := m.withStoreProxyMutationAndReload(name, func(storeSource *source.StoreSource) error {
		if err := storeSource.AddProxy(cfg); err != nil {
			if errors.Is(err, source.ErrAlreadyExists) {
				return fmt.Errorf("%w: %v", configmgmt.ErrConflict, err)
			}
			return err
		}
		return nil
	})
	if err != nil {
		return nil, err
	}
	log.Infof("store: created proxy %q", name)
	return persisted, nil
}

View on GitHub (pinned to 6c8a8d0a97)

Solutions

  1. Read the wrapped validation message; it names the exact field and rule that failed.
  2. Compare your body against a known-good proxy via GET /api/store/proxies and mirror the required fields.
  3. Ensure 'name' is set, 'type' is one of the supported types (tcp/udp/http/https/tcpmux/stcp/sudp/xtcp), and type-specific fields (remotePort, subdomain, locations, secretKey...) are present.
  4. Validate locally with the same v1 validation package before posting if you drive the Go API directly.

Example fix

# before (missing remotePort for tcp)
curl -X POST http://127.0.0.1:7400/api/store/proxies \
  -d '{"type":"tcp","name":"ssh","localPort":22}'
# invalid argument: validation error: remotePort required

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

Strategy: validation

Validate before calling

// Mirror required fields before POST.
body := map[string]any{"type": "tcp", "name": name, "localPort": lp, "remotePort": rp}
if name == "" || body["type"] == "" || lp <= 0 || rp <= 0 {
    return errors.New("proxy payload incomplete")
}

Try / catch

if _, err := mgr.CreateStoreProxy(cfg); err != nil {
    if errors.Is(err, configmgmt.ErrInvalidArgument) {
        // err text carries the validation detail; fix the offending field
    }
}

Prevention

When it happens

Trigger: POST /api/store/proxies with a body missing required fields for the proxy type (e.g. a tcp proxy without remotePort), an invalid or empty name, unsupported type value, or a plugin block that fails validation. Also triggered by structurally valid JSON whose field values violate v1 validation rules.

Common situations: Switching proxy type and forgetting type-specific fields (udp needs nothing extra, tcp needs remotePort); typos in the type discriminator; submitting YAML-shaped keys to a JSON/TOML endpoint; port values outside 1-65535 or colliding localPort semantics.

Related errors


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