{"record":{"id":"fcc27ba3972d9f56","repo":"fatedier/frp","slug":"invalid-argument-invalid-visitor-config-type-is","errorCode":null,"errorMessage":"invalid argument: invalid visitor config: type is required","messagePattern":"invalid argument: invalid visitor config: type is required","errorType":"http","errorClass":"configmgmt.ErrInvalidArgument","httpStatus":400,"severity":"error","filePath":"client/config_manager.go","lineNumber":306,"sourceCode":"\t\t\t}\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tlog.Infof(\"store: created visitor %q\", name)\n\treturn persisted, nil\n}\n\nfunc (m *serviceConfigManager) UpdateStoreVisitor(name string, cfg v1.VisitorConfigurer) (v1.VisitorConfigurer, error) {\n\tif name == \"\" {\n\t\treturn nil, fmt.Errorf(\"%w: visitor name is required\", configmgmt.ErrInvalidArgument)\n\t}\n\tif cfg == nil {\n\t\treturn nil, fmt.Errorf(\"%w: invalid visitor config: type is required\", configmgmt.ErrInvalidArgument)\n\t}\n\tbodyName := cfg.GetBaseConfig().Name\n\tif bodyName != name {\n\t\treturn nil, fmt.Errorf(\"%w: visitor name in URL must match name in body\", configmgmt.ErrInvalidArgument)\n\t}\n\tif err := m.validateStoreVisitorConfigurer(cfg); err != nil {\n\t\treturn nil, fmt.Errorf(\"%w: validation error: %v\", configmgmt.ErrInvalidArgument, err)\n\t}\n\n\tpersisted, err := m.withStoreVisitorMutationAndReload(name, func(storeSource *source.StoreSource) error {\n\t\tif err := storeSource.UpdateVisitor(cfg); err != nil {\n\t\t\tif errors.Is(err, source.ErrNotFound) {\n\t\t\t\treturn fmt.Errorf(\"%w: %v\", configmgmt.ErrNotFound, err)\n\t\t\t}\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})","sourceCodeStart":288,"sourceCodeEnd":324,"githubUrl":"https://github.com/fatedier/frp/blob/6c8a8d0a97d03b44e9528d30b30c70cb9d61b405/client/config_manager.go#L288-L324","documentation":"Returned by UpdateStoreVisitor when the decoded body yields a nil VisitorConfigurer. The controller maps the body's \"type\" discriminator to a concrete visitor configurer; a body with no valid type (missing, misspelled, wrong case, or unparseable payload) decodes to nil and fails this guard with 'type is required' (ErrInvalidArgument → HTTP 400).","triggerScenarios":"PUT /api/store/visitors/{name} with a body missing \"type\"; type set to a proxy type like \"tcp\" instead of a visitor type (stcp/sudp/xtcp); sending YAML or form data where JSON is expected.","commonSituations":"Copying a proxy definition as the base for a visitor and forgetting to change type; case errors (\"STCP\"); clients defaulting Content-Type incorrectly so the strict decoder rejects the body.","solutions":["Set \"type\" to a valid visitor type: stcp, sudp, or xtcp (lowercase) in the JSON body.","Verify Content-Type: application/json and that the payload parses as JSON.","Round-trip from GET /api/store/visitors/{name} and edit from the returned shape."],"exampleFix":"# before\ncurl -XPUT .../api/store/visitors/db-v -d '{\"name\":\"db-v\",\"serverName\":\"db\",...}'\n# 400 invalid visitor config: type is required\n\n# after\ncurl -XPUT .../api/store/visitors/db-v -d '{\"type\":\"stcp\",\"name\":\"db-v\",\"serverName\":\"db\",...}'","handlingStrategy":"validation","validationCode":"// Require a valid visitor type before PUT.\nvisitorTypes := map[string]bool{\"stcp\": true, \"sudp\": true, \"xtcp\": true}\nif !visitorTypes[body.Type] {\n    return fmt.Errorf(\"missing or invalid visitor type %q (want stcp/sudp/xtcp)\", body.Type)\n}","typeGuard":null,"tryCatchPattern":"if _, err := mgr.UpdateStoreVisitor(name, cfg); err != nil {\n    if errors.Is(err, configmgmt.ErrInvalidArgument) && strings.Contains(err.Error(), \"type is required\") {\n        // decoding yielded nil configurer: set type to stcp/sudp/xtcp and resend as JSON\n    }\n}","preventionTips":["Remember visitors support only stcp/sudp/xtcp — never proxy types like tcp/http","Round-trip from GET /api/store/visitors/{name} before editing"],"tags":["frp","frpc","store","visitor","validation","json"],"backgroundTag":null,"analyzedSha":"6c8a8d0a97d03b44e9528d30b30c70cb9d61b405","analyzedAt":"2026-08-15T06:53:27.215Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}