{"record":{"id":"b233649ac264a295","repo":"fatedier/frp","slug":"unmarshal-proxyconfig-error-v","errorCode":null,"errorMessage":"unmarshal ProxyConfig error: %v","messagePattern":"unmarshal ProxyConfig error: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/config/v1/decode.go","lineNumber":59,"sourceCode":"\tPlugin jsonx.RawMessage `json:\"plugin,omitempty\"`\n}\n\nfunc DecodeProxyConfigurerJSON(b []byte, options DecodeOptions) (ProxyConfigurer, error) {\n\tif isJSONNull(b) {\n\t\treturn nil, errors.New(\"type is required\")\n\t}\n\n\tvar env typedEnvelope\n\tif err := jsonx.Unmarshal(b, &env); err != nil {\n\t\treturn nil, err\n\t}\n\n\tconfigurer := NewProxyConfigurerByType(ProxyType(env.Type))\n\tif configurer == nil {\n\t\treturn nil, fmt.Errorf(\"unknown proxy type: %s\", env.Type)\n\t}\n\tif err := decodeJSONWithOptions(b, configurer, options); err != nil {\n\t\treturn nil, fmt.Errorf(\"unmarshal ProxyConfig error: %v\", err)\n\t}\n\n\tif len(env.Plugin) > 0 && !isJSONNull(env.Plugin) {\n\t\tplugin, err := DecodeClientPluginOptionsJSON(env.Plugin, options)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"unmarshal proxy plugin error: %v\", err)\n\t\t}\n\t\tconfigurer.GetBaseConfig().Plugin = plugin\n\t}\n\treturn configurer, nil\n}\n\nfunc DecodeVisitorConfigurerJSON(b []byte, options DecodeOptions) (VisitorConfigurer, error) {\n\tif isJSONNull(b) {\n\t\treturn nil, errors.New(\"type is required\")\n\t}\n\n\tvar env typedEnvelope","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/fatedier/frp/blob/6c8a8d0a97d03b44e9528d30b30c70cb9d61b405/pkg/config/v1/decode.go#L41-L77","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n{ \"type\": \"tcp\", \"localPort\": \"80\" }\n\n// after\n{ \"type\": \"tcp\", \"localPort\": 80 }","handlingStrategy":"try-catch","validationCode":"// Optional pre-flight: strict-decode into a map to find unknown/mistyped fields first.\nfunc lintProxyJSON(b []byte) error {\n\tvar probe map[string]any\n\tif err := json.Unmarshal(b, &probe); err != nil {\n\t\treturn err\n\t}\n\tif t, _ := probe[\"type\"].(string); t == \"\" {\n\t\treturn fmt.Errorf(\"proxy entry missing type\")\n\t}\n\treturn nil // full schema checks still happen in decodeJSONWithOptions\n}","typeGuard":null,"tryCatchPattern":"proxyCfg, err := v1.DecodeProxyConfigurerJSON(raw, opts)\nif err != nil {\n\tif strings.Contains(err.Error(), \"unmarshal ProxyConfig error\") {\n\t\t// err wraps the json field error; log raw proxy JSON + err to pinpoint the field\n\t\tlog.Printf(\"proxy decode failed: %v; payload: %s\", err, raw)\n\t}\n\treturn err\n}","preventionTips":["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."],"tags":["go","frp","config","json","proxy","decode","type-mismatch"],"backgroundTag":null,"analyzedSha":"6c8a8d0a97d03b44e9528d30b30c70cb9d61b405","analyzedAt":"2026-08-15T06:53:27.215Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}