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

  1. Make the block key and "type" identical (stcp/stcp, sudp/sudp, xtcp/xtcp), lowercase.
  2. Set both from a single source variable in generating code.
  3. 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

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


AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15). Data as JSON: /api/errors/1f8cc87adf59d9c6. Report an issue: GitHub.