fatedier/frp · error · configmgmt.ErrInvalidArgument
invalid argument: invalid proxy config: type is required
Error message
invalid argument: invalid proxy config: type is required
What it means
Returned by UpdateStoreProxy when the decoded request body produced a nil ProxyConfigurer. In practice the frpc controller decodes the body's type discriminator into a concrete configurer; a body without a recognized 'type' (or a totally unparseable body) yields nil, which this guard rejects as 'type is required' with ErrInvalidArgument.
Source
Thrown at client/config_manager.go:205
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
}
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
})View on GitHub (pinned to 6c8a8d0a97)
Solutions
- Include a valid "type" field in the JSON body (tcp, udp, http, https, tcpmux, stcp, sudp, xtcp — lowercase).
- Confirm the Content-Type and that the body is JSON, matching what GET /api/store/proxies/{name} returns.
- Round-trip: GET the current proxy, modify fields, PUT the whole object back.
Example fix
# before
curl -X PUT http://127.0.0.1:7400/api/store/proxies/ssh -d '{"name":"ssh","localPort":22,"remotePort":6022}'
# 400 invalid proxy config: type is required
# 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
// Require a known proxy type before PUT.
validTypes := map[string]bool{"tcp":true,"udp":true,"http":true,"https":true,"tcpmux":true,"stcp":true,"sudp":true,"xtcp":true}
if !validTypes[body.Type] {
return fmt.Errorf("missing or unsupported proxy type %q", body.Type)
} Try / catch
if _, err := mgr.UpdateStoreProxy(name, cfg); err != nil {
if errors.Is(err, configmgmt.ErrInvalidArgument) && strings.Contains(err.Error(), "type is required") {
// body decoding produced no configurer: fix type field / content-type
}
} Prevention
- Always include lowercase "type" in proxy bodies
- Send Content-Type: application/json matching GET responses
When it happens
Trigger: PUT /api/store/proxies/{name} with a body missing the "type" field, with an unsupported type string, or with an empty body; sending form-encoded or YAML data to a JSON endpoint so decoding yields nothing.
Common situations: Copy-pasting a proxy definition from docs that omit type; typos like "TCP" (case-sensitive) or "tcpv2"; sending the body as query parameters instead of JSON.
Related errors
- invalid argument: proxy name is required
- invalid argument: validation error: %v
- invalid argument: proxy name in URL must match name in body
- invalid argument: invalid visitor config: type is required
- not found: proxy %q
AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15).
Data as JSON: /api/errors/aefe849f010ba437.
Report an issue: GitHub.