fatedier/frp · error
visitor type block %q does not match type %q
Error message
visitor type block %q does not match type %q
What it means
Returned by VisitorDefinition.Validate when exactly one visitor type block is present but its kind does not match the top-level "type" string — e.g. type "stcp" while the populated block is "xtcp".
Source
Thrown at client/http/model/visitor_definition.go:35
}
func (p *VisitorDefinition) Validate(pathName string, isUpdate bool) error {
if strings.TrimSpace(p.Name) == "" {
return fmt.Errorf("visitor name is required")
}
if !IsVisitorType(p.Type) {
return fmt.Errorf("invalid visitor type: %s", p.Type)
}
if isUpdate && pathName != "" && pathName != p.Name {
return fmt.Errorf("visitor name in URL must match name in body")
}
_, blockType, blockCount := p.activeBlock()
if blockCount != 1 {
return fmt.Errorf("exactly one visitor type block is required")
}
if blockType != p.Type {
return fmt.Errorf("visitor type block %q does not match type %q", blockType, p.Type)
}
return nil
}
func (p *VisitorDefinition) ToConfigurer() (v1.VisitorConfigurer, error) {
block, _, _ := p.activeBlock()
if block == nil {
return nil, fmt.Errorf("exactly one visitor type block is required")
}
cfg := block
cfg.GetBaseConfig().Name = p.Name
cfg.GetBaseConfig().Type = p.Type
return cfg, nil
}
func VisitorDefinitionFromConfigurer(cfg v1.VisitorConfigurer) (VisitorDefinition, error) {
if cfg == nil {View on GitHub (pinned to 6c8a8d0a97)
Solutions
- Make the block key and "type" identical (stcp/stcp, sudp/sudp, xtcp/xtcp), lowercase.
- Set both from a single source variable in generating code.
- Re-check after switching visitor kinds that the old block was removed.
Example fix
// before
{"name": "v", "type": "xtcp", "stcp": {"serverName": "svc"}}
// after
{"name": "v", "type": "stcp", "stcp": {"serverName": "svc"}} Defensive patterns
Strategy: validation
Validate before calling
func visitorBlockMatchesType(def map[string]any) bool {
for _, k := range []string{"stcp","sudp","xtcp"} {
if def[k] != nil { return def["type"] == k }
}
return false
} Prevention
- Derive type from the populated block key automatically.
- Never edit type and block independently.
- Lint configs for type/block agreement before deploy.
When it happens
Trigger: {"name":"v","type":"xtcp","stcp":{...}} — the block and type field disagree.
Common situations: Editing the "type" field without swapping the block; generated configs pulling type and block from different variables; copy-paste between visitor definitions.
Related errors
- visitor name is required
- invalid visitor type: %s
- exactly one visitor type block is required
- proxy name is required
- invalid proxy type: %s
AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15).
Data as JSON: /api/errors/1f8cc87adf59d9c6.
Report an issue: GitHub.