{"record":{"id":"b6c149e7118bfc1d","repo":"fatedier/frp","slug":"not-found-visitor-q","errorCode":null,"errorMessage":"not found: visitor %q","messagePattern":"not found: visitor %q","errorType":"http","errorClass":"configmgmt.ErrNotFound","httpStatus":404,"severity":"error","filePath":"client/config_manager.go","lineNumber":273,"sourceCode":"\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn storeSource.GetAllVisitors()\n}\n\nfunc (m *serviceConfigManager) GetStoreVisitor(name string) (v1.VisitorConfigurer, error) {\n\tif name == \"\" {\n\t\treturn nil, fmt.Errorf(\"%w: visitor name is required\", configmgmt.ErrInvalidArgument)\n\t}\n\n\tstoreSource, err := m.storeSourceOrError()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tcfg := storeSource.GetVisitor(name)\n\tif cfg == nil {\n\t\treturn nil, fmt.Errorf(\"%w: visitor %q\", configmgmt.ErrNotFound, name)\n\t}\n\treturn cfg, nil\n}\n\nfunc (m *serviceConfigManager) CreateStoreVisitor(cfg v1.VisitorConfigurer) (v1.VisitorConfigurer, error) {\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\tname := cfg.GetBaseConfig().Name\n\tpersisted, err := m.withStoreVisitorMutationAndReload(name, func(storeSource *source.StoreSource) error {\n\t\tif err := storeSource.AddVisitor(cfg); err != nil {\n\t\t\tif errors.Is(err, source.ErrAlreadyExists) {\n\t\t\t\treturn fmt.Errorf(\"%w: %v\", configmgmt.ErrConflict, err)\n\t\t\t}\n\t\t\treturn err\n\t\t}\n\t\treturn nil","sourceCodeStart":255,"sourceCodeEnd":291,"githubUrl":"https://github.com/fatedier/frp/blob/6c8a8d0a97d03b44e9528d30b30c70cb9d61b405/client/config_manager.go#L255-L291","documentation":"Returned by GetStoreVisitor when the store source holds no visitor with the requested name (storeSource.GetVisitor(name) returned nil). Wrapped as configmgmt.ErrNotFound and surfaced as HTTP 404. Visitors (stcp/sudp/xtcp companions) are stored separately from proxies.","triggerScenarios":"GET /api/store/visitors/{name} for a visitor that was never created, was deleted, or whose name is misspelled; querying the proxy name instead of the visitor name.","commonSituations":"Confusing the proxy name (e.g. 'db') with its visitor name (e.g. 'db-visitor'); assuming visitors defined in the static TOML file appear in the store; stale documentation naming.","solutions":["List visitors with GET /api/store/visitors and use the exact name.","Create the visitor with POST /api/store/visitors if it should exist.","Check you targeted the correct frpc instance (the side that runs the visitor)."],"exampleFix":"# before\ncurl .../api/store/visitors/db   # 404 not found: visitor \"db\"\n\n# after\ncurl .../api/store/visitors | jq '.[].name'\ncurl .../api/store/visitors/db-visitor","handlingStrategy":"try-catch","validationCode":"// Confirm via list before GET by name.\nfunc visitorExists(base, name string) bool {\n    resp, _ := http.Get(base + \"/api/store/visitors\")\n    defer resp.Body.Close()\n    var list []struct{ Name string }\n    json.NewDecoder(resp.Body).Decode(&list)\n    for _, v := range list { if v.Name == name { return true } }\n    return false\n}","typeGuard":null,"tryCatchPattern":"cfg, err := mgr.GetStoreVisitor(name)\nif err != nil {\n    if errors.Is(err, configmgmt.ErrNotFound) {\n        // create it or report cleanly; check you didn't pass the proxy name\n    }\n}","preventionTips":["Use exact names from GET /api/store/visitors","Remember visitors live on the client side that dials in, not on the proxy-owning side"],"tags":["frp","frpc","store","visitor","not-found"],"backgroundTag":null,"analyzedSha":"6c8a8d0a97d03b44e9528d30b30c70cb9d61b405","analyzedAt":"2026-08-15T06:53:27.215Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}