fatedier/frp · error
unmarshal ProxyConfig error: %v
Error message
unmarshal ProxyConfig error: %v
What it means
DecodeProxyConfigurerJSON fails at decodeJSONWithOptions when the proxy object's fields cannot be unmarshalled into the typed ProxyConfigurer selected by "type". The underlying json unmarshal error is wrapped with 'unmarshal ProxyConfig error'. This means the type was recognized, but field names or values inside the proxy object do not match the struct for that proxy type.
Source
Thrown at pkg/config/v1/decode.go:59
Plugin jsonx.RawMessage `json:"plugin,omitempty"`
}
func DecodeProxyConfigurerJSON(b []byte, options DecodeOptions) (ProxyConfigurer, error) {
if isJSONNull(b) {
return nil, errors.New("type is required")
}
var env typedEnvelope
if err := jsonx.Unmarshal(b, &env); err != nil {
return nil, err
}
configurer := NewProxyConfigurerByType(ProxyType(env.Type))
if configurer == nil {
return nil, fmt.Errorf("unknown proxy type: %s", env.Type)
}
if err := decodeJSONWithOptions(b, configurer, options); err != nil {
return nil, fmt.Errorf("unmarshal ProxyConfig error: %v", err)
}
if len(env.Plugin) > 0 && !isJSONNull(env.Plugin) {
plugin, err := DecodeClientPluginOptionsJSON(env.Plugin, options)
if err != nil {
return nil, fmt.Errorf("unmarshal proxy plugin error: %v", err)
}
configurer.GetBaseConfig().Plugin = plugin
}
return configurer, nil
}
func DecodeVisitorConfigurerJSON(b []byte, options DecodeOptions) (VisitorConfigurer, error) {
if isJSONNull(b) {
return nil, errors.New("type is required")
}
var env typedEnvelopeView on GitHub (pinned to 6c8a8d0a97)
Solutions
- Read the wrapped error text — it names the exact offending field and reason; fix that field's type or name.
- Match the schema for the declared proxy type (e.g. tcp proxies take localPort/localIP as their proper types).
- If strict decoding rejected an unknown field, remove the stale field or disable strict mode in DecodeOptions.
Example fix
// before
{ "type": "tcp", "localPort": "80" }
// after
{ "type": "tcp", "localPort": 80 } Defensive patterns
Strategy: try-catch
Validate before calling
// Optional pre-flight: strict-decode into a map to find unknown/mistyped fields first.
func lintProxyJSON(b []byte) error {
var probe map[string]any
if err := json.Unmarshal(b, &probe); err != nil {
return err
}
if t, _ := probe["type"].(string); t == "" {
return fmt.Errorf("proxy entry missing type")
}
return nil // full schema checks still happen in decodeJSONWithOptions
} Try / catch
proxyCfg, err := v1.DecodeProxyConfigurerJSON(raw, opts)
if err != nil {
if strings.Contains(err.Error(), "unmarshal ProxyConfig error") {
// err wraps the json field error; log raw proxy JSON + err to pinpoint the field
log.Printf("proxy decode failed: %v; payload: %s", err, raw)
}
return err
} Prevention
- Use native JSON types: numbers unquoted, booleans unquoted.
- Validate configs in CI with the same frp version you deploy.
- Prefer TOML with schema-aware editor tooling to catch field typos.
When it happens
Trigger: A proxy entry with a field of the wrong JSON type (e.g. "localPort": "80" as string instead of number), an unknown field when strict decoding is enabled via DecodeOptions, or a structural mismatch such as passing an object where an array is expected. Reached through DecodeClientConfigJSON or a direct DecodeProxyConfigurerJSON call.
Common situations: Renamed/removed fields across frp major versions (INI -> TOML migration leftovers); strict-mode schemas (like EnableStrictDecoding options) rejecting unknown fields; YAML-to-JSON conversion quirks turning numbers into strings.
Related errors
- unknown proxy type: %s
- unmarshal VisitorConfig error: %v
- unmarshal ClientPluginOptions error: %v
- unmarshal VisitorPluginOptions error: %v
- decode proxy at index %d: %w
AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15).
Data as JSON: /api/errors/b233649ac264a295.
Report an issue: GitHub.