{"record":{"id":"67561d853839dfcb","repo":"fatedier/frp","slug":"unmarshal-visitorconfig-error-v","errorCode":null,"errorMessage":"unmarshal VisitorConfig error: %v","messagePattern":"unmarshal VisitorConfig error: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/config/v1/decode.go","lineNumber":87,"sourceCode":"\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\n\tif err := jsonx.Unmarshal(b, &env); err != nil {\n\t\treturn nil, err\n\t}\n\n\tconfigurer := NewVisitorConfigurerByType(VisitorType(env.Type))\n\tif configurer == nil {\n\t\treturn nil, fmt.Errorf(\"unknown visitor type: %s\", env.Type)\n\t}\n\tif err := decodeJSONWithOptions(b, configurer, options); err != nil {\n\t\treturn nil, fmt.Errorf(\"unmarshal VisitorConfig error: %v\", err)\n\t}\n\n\tif len(env.Plugin) > 0 && !isJSONNull(env.Plugin) {\n\t\tplugin, err := DecodeVisitorPluginOptionsJSON(env.Plugin, options)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"unmarshal visitor plugin error: %v\", err)\n\t\t}\n\t\tconfigurer.GetBaseConfig().Plugin = plugin\n\t}\n\treturn configurer, nil\n}\n\nfunc DecodeClientPluginOptionsJSON(b []byte, options DecodeOptions) (TypedClientPluginOptions, error) {\n\tif isJSONNull(b) {\n\t\treturn TypedClientPluginOptions{}, nil\n\t}\n\n\tvar env typedEnvelope","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/fatedier/frp/blob/6c8a8d0a97d03b44e9528d30b30c70cb9d61b405/pkg/config/v1/decode.go#L69-L105","documentation":"DecodeVisitorConfigurerJSON fails at decodeJSONWithOptions when the visitor object's fields cannot be unmarshalled into the typed VisitorConfigurer selected by \"type\". The underlying json error is wrapped as 'unmarshal VisitorConfig error'. The visitor type was recognized, but field names or value types inside the visitor object don't match its struct.","triggerScenarios":"A visitor entry with wrong-typed fields (e.g. \"bindPort\": \"6000\" as a string, or \"serverName\" given as a number), or unknown fields under strict DecodeOptions. Reached via DecodeClientConfigJSON's visitors loop or a direct DecodeVisitorConfigurerJSON call.","commonSituations":"Config migration tools emitting strings for numeric fields; stale field names from older frp versions (secretKey casing); strict mode rejecting extra keys.","solutions":["Read the wrapped error — it identifies the exact field; correct its type (numbers as numbers, strings as strings).","Align field names with the visitor schema for the declared type (name, secretKey, serverName, bindAddr, bindPort).","Remove unrecognized fields or relax strict decoding in DecodeOptions."],"exampleFix":"// before\n{ \"type\": \"stcp\", \"bindPort\": \"6000\" }\n\n// after\n{ \"type\": \"stcp\", \"bindPort\": 6000 }","handlingStrategy":"try-catch","validationCode":"// Pre-check visitor entries for obviously wrong field types.\nfunc lintVisitorJSON(b []byte) error {\n\tvar probe struct {\n\t\tType     string `json:\"type\"`\n\t\tBindPort any    `json:\"bindPort\"`\n\t}\n\tif err := json.Unmarshal(b, &probe); err != nil {\n\t\treturn err\n\t}\n\tif bp, ok := probe.BindPort.(string); ok {\n\t\treturn fmt.Errorf(\"bindPort must be a number, got string %q\", bp)\n\t}\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":"if _, err := v1.DecodeClientConfigJSON(b, opts); err != nil {\n\tif strings.Contains(err.Error(), \"unmarshal VisitorConfig error\") {\n\t\t// wrapped json error names the field; fix that visitors[] entry\n\t}\n\treturn err\n}","preventionTips":["Keep numeric visitor fields numeric in JSON/TOML.","Use current field names (bindPort, secretKey, serverName).","Test visitor configs with frpc verify before deploy."],"tags":["go","frp","config","json","visitor","decode","type-mismatch"],"backgroundTag":null,"analyzedSha":"6c8a8d0a97d03b44e9528d30b30c70cb9d61b405","analyzedAt":"2026-08-15T06:53:27.215Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}