fatedier/frp · error
unknown visitor config type
Error message
unknown visitor config type
What it means
Error from ValidateVisitorConfigurer: the visitor configurer is not one of *v1.STCPVisitorConfig, *v1.SUDPVisitorConfig, or *v1.XTCPVisitorConfig. Visitors exist only for the secret/p2p proxy types (stcp, sudp, xtcp); any other concrete type — or a nil interface — falls through to this default error after base validation. Usually a programmatic/embedding issue since file configs reject unknown visitor types at decode time.
Source
Thrown at pkg/config/v1/validation/visitor.go:37
"fmt"
"slices"
v1 "github.com/fatedier/frp/pkg/config/v1"
)
func ValidateVisitorConfigurer(c v1.VisitorConfigurer) error {
base := c.GetBaseConfig()
if err := validateVisitorBaseConfig(base); err != nil {
return err
}
switch v := c.(type) {
case *v1.STCPVisitorConfig:
case *v1.SUDPVisitorConfig:
case *v1.XTCPVisitorConfig:
return validateXTCPVisitorConfig(v)
default:
return errors.New("unknown visitor config type")
}
return nil
}
func validateVisitorBaseConfig(c *v1.VisitorBaseConfig) error {
if c.Name == "" {
return errors.New("name is required")
}
if c.ServerName == "" {
return errors.New("server name is required")
}
if c.BindPort == 0 {
return errors.New("bind port is required")
}
return nil
}View on GitHub (pinned to 6c8a8d0a97)
Solutions
- Use one of the three supported visitor configurers: *v1.STCPVisitorConfig, *v1.SUDPVisitorConfig, *v1.XTCPVisitorConfig.
- Guard against nil before validating: if c == nil { ... }.
- Verify you are pairing the visitor with a matching stcp/sudp/xtcp proxy — tcp/udp/http proxies have no visitors.
Example fix
// before
var vc v1.VisitorConfigurer
err := validation.ValidateVisitorConfigurer(vc)
// after
vc := &v1.STCPVisitorConfig{
VisitorBaseConfig: &v1.VisitorBaseConfig{
Name: "stcpv", ServerName: "stcp-srv", BindPort: 9000,
},
SecretKey: "secret",
}
err := validation.ValidateVisitorConfigurer(vc) Defensive patterns
Strategy: type-guard
Validate before calling
func isKnownVisitorType(c v1.VisitorConfigurer) bool {
switch c.(type) {
case *v1.STCPVisitorConfig, *v1.SUDPVisitorConfig, *v1.XTCPVisitorConfig:
return true
}
return false
} Type guard
func isKnownVisitorType(c v1.VisitorConfigurer) bool {
switch c.(type) {
case *v1.STCPVisitorConfig, *v1.SUDPVisitorConfig, *v1.XTCPVisitorConfig:
return true
default:
return false
}
} Try / catch
if !isKnownVisitorType(cfg) {
return fmt.Errorf("unsupported visitor configurer %T", cfg)
}
if err := validation.ValidateVisitorConfigurer(cfg); err != nil { return err } Prevention
- Only stcp/sudp/xtcp have visitors — do not build visitors for tcp/udp/http.
- Nil-check visitor configs before validating.
- Keep the frp library version aligned with the visitor types you construct.
When it happens
Trigger: Calling validation.ValidateVisitorConfigurer(c) with a nil visitor configurer, a custom struct implementing VisitorConfigurer, or a value (not pointer) of a visitor config that no longer matches the case types.
Common situations: Embedding frp as a library and constructing visitor configs of the wrong type or leaving them nil; mixed library versions where the visitor type set differs; copying example code that validates a visitor for a proxy type that has no visitor support (e.g. tcp).
Related errors
AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15).
Data as JSON: /api/errors/b4b8c969f3602edb.
Report an issue: GitHub.