{"record":{"id":"316529e9b0f6878d","repo":"fatedier/frp","slug":"proxy-name-cannot-be-empty","errorCode":null,"errorMessage":"proxy name cannot be empty","messagePattern":"proxy name cannot be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/config/source/store.go","lineNumber":103,"sourceCode":"\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\")\n\t\t}\n\t\ts.visitors[name] = visitorCfg\n\t}\n","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/fatedier/frp/blob/6c8a8d0a97d03b44e9528d30b30c70cb9d61b405/pkg/config/source/store.go#L85-L121","documentation":"A proxy entry in the store file decoded successfully but its base config has an empty Name. Every stored proxy must carry a non-empty unique \"name\" because the in-memory store is a map keyed by name; a nameless entry cannot be represented and loading is aborted.","triggerScenarios":"A hand-written or machine-generated proxies array element that omits the \"name\" field entirely, or sets it to \"\". Loading stops at the first such entry, so the whole StoreSource fails to construct.","commonSituations":"Authoring store files by hand or with a template that forgot the name; a provisioning script that emits name for most entries but misses one; renaming fields during a config migration.","solutions":["Open the store file and locate the proxy element (the error surfaces on first nameless one; scan the whole proxies array)","Add a unique, non-empty \"name\" to every element that lacks one","Alternatively delete the incomplete entry if it was scaffolding","Re-run the process and confirm NewStoreSource succeeds"],"exampleFix":"// before\n{ \"proxies\": [ { \"type\": \"tcp\", \"localPort\": 22 } ] }\n\n// after\n{ \"proxies\": [ { \"type\": \"tcp\", \"name\": \"ssh\", \"localPort\": 22 } ] }","handlingStrategy":"validation","validationCode":"func validateStoreNames(path string) error {\n\tdata, _ := os.ReadFile(path)\n\tvar raw struct {\n\t\tProxies []struct{ Name string `json:\"name\"` } `json:\"proxies\"`\n\t}\n\tif json.Unmarshal(data, &raw) != nil {\n\t\treturn nil\n\t}\n\tfor i, p := range raw.Proxies {\n\t\tif strings.TrimSpace(p.Name) == \"\" {\n\t\t\treturn fmt.Errorf(\"proxies[%d] has empty name\", i)\n\t\t}\n\t}\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat 'name' as a required field in any template or script that produces store files","CI-lint generated store files for required fields before deployment","Prefer the Add/Update API over file authoring so validation is enforced"],"tags":["json","config","validation","required-field","go"],"backgroundTag":null,"analyzedSha":"6c8a8d0a97d03b44e9528d30b30c70cb9d61b405","analyzedAt":"2026-08-15T06:53:27.215Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}