{"record":{"id":"1524d60c6691a0cc","repo":"fatedier/frp","slug":"failed-to-decode-proxy-at-index-d-w","errorCode":null,"errorMessage":"failed to decode proxy at index %d: %w","messagePattern":"failed to decode proxy at index (.+?): %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/config/source/store.go","lineNumber":99,"sourceCode":"\n\ttype rawStoreData struct {\n\t\tProxies  []jsonx.RawMessage `json:\"proxies,omitempty\"`\n\t\tVisitors []jsonx.RawMessage `json:\"visitors,omitempty\"`\n\t}\n\tstored := rawStoreData{}\n\tif err := jsonx.Unmarshal(data, &stored); err != nil {\n\t\treturn fmt.Errorf(\"failed to parse JSON: %w\", err)\n\t}\n\n\ts.proxies = make(map[string]v1.ProxyConfigurer)\n\ts.visitors = make(map[string]v1.VisitorConfigurer)\n\n\tfor i, proxyData := range stored.Proxies {\n\t\tproxyCfg, err := v1.DecodeProxyConfigurerJSON(proxyData, v1.DecodeOptions{\n\t\t\tDisallowUnknownFields: false,\n\t\t})\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to decode proxy at index %d: %w\", i, err)\n\t\t}\n\t\tname := proxyCfg.GetBaseConfig().Name\n\t\tif name == \"\" {\n\t\t\treturn fmt.Errorf(\"proxy name cannot be empty\")\n\t\t}\n\t\ts.proxies[name] = proxyCfg\n\t}\n\n\tfor i, visitorData := range stored.Visitors {\n\t\tvisitorCfg, err := v1.DecodeVisitorConfigurerJSON(visitorData, v1.DecodeOptions{\n\t\t\tDisallowUnknownFields: false,\n\t\t})\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to decode visitor at index %d: %w\", i, err)\n\t\t}\n\t\tname := visitorCfg.GetBaseConfig().Name\n\t\tif name == \"\" {\n\t\t\treturn fmt.Errorf(\"visitor name cannot be empty\")","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/fatedier/frp/blob/6c8a8d0a97d03b44e9528d30b30c70cb9d61b405/pkg/config/source/store.go#L81-L117","documentation":"While loading the store, DecodeProxyConfigurerJSON failed for the i-th element of the proxies array. Decoding is two-stage: the entry's \"type\" discriminator must map to a registered ProxyConfigurer type, then the payload must unmarshal into that type. Because DisallowUnknownFields is false, unknown fields alone do NOT trigger this — a bad/missing \"type\" string or a structurally incompatible payload does.","triggerScenarios":"A stored proxy entry whose \"type\" is misspelled (\"tcp\" vs \"tpc\") or missing; a store file written by a NEWER frp version containing a proxy type this older build does not know; an entry where the value of \"type\" is not a string; a payload that cannot unmarshal into the target config struct (e.g. remotePort as a string).","commonSituations":"Downgrading frp after a newer release wrote modern proxy types into the store; hand-authoring the store file with the wrong discriminator name; a custom/enterprise proxy type that was compiled in before but not in the current binary.","solutions":["Open the store file, navigate to the proxies array element at the index reported in the error message (index is 0-based)","Verify its \"type\" value is one of the proxy types supported by the RUNNING frp version (tcp, udp, xtcp, stcp, sudp, http, https, tcpmux, plugin variants)","If the type is from a newer frp release, upgrade frp to at least the version that wrote the file","Fix the typo'd/missing \"type\" field or remove the offending entry, then retry"],"exampleFix":"// before (store.json, proxies[2])\n{ \"type\": \"htp\", \"name\": \"dashboard\" }\n\n// after\n{ \"type\": \"http\", \"name\": \"dashboard\" }","handlingStrategy":"validation","validationCode":"var supportedProxyTypes = map[string]bool{\n\t\"tcp\": true, \"udp\": true, \"xtcp\": true, \"stcp\": true, \"sudp\": true,\n\t\"http\": true, \"https\": true, \"tcpmux\": true,\n}\n\nfunc validateStoreTypes(path string) error {\n\tdata, _ := os.ReadFile(path)\n\tvar raw struct {\n\t\tProxies []json.RawMessage `json:\"proxies\"`\n\t}\n\tif json.Unmarshal(data, &raw) != nil {\n\t\treturn nil // parse errors handled separately\n\t}\n\tfor i, p := range raw.Proxies {\n\t\tvar t struct{ Type string `json:\"type\"` }\n\t\tif json.Unmarshal(p, &t) != nil || !supportedProxyTypes[t.Type] {\n\t\t\treturn fmt.Errorf(\"proxies[%d]: unsupported type %q for this frp build\", i, t.Type)\n\t\t}\n\t}\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":"if _, err := source.NewStoreSource(cfg); err != nil {\n\tvar idx int\n\tif _, e := fmt.Sscanf(err.Error(), \"failed to decode proxy at index %d\", &idx); e == nil {\n\t\t// point operator at the exact array element, suggest version mismatch\n\t}\n}","preventionTips":["Pin the frp version fleet-wide so store files never contain types a binary can't decode","When downgrading, regenerate the store with the older version before pointing it at the file","Automate store-file generation through the API rather than writing raw JSON"],"tags":["json","schema","version-compat","config","decoding","go"],"backgroundTag":null,"analyzedSha":"6c8a8d0a97d03b44e9528d30b30c70cb9d61b405","analyzedAt":"2026-08-15T06:53:27.215Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}