fatedier/frp · error

visitor %s: %v

Error message

visitor %s: %v

What it means

Aggregate wrapper for visitors: ValidateVisitorConfigurer failed for one [[visitors]] entry and the error is prefixed with the visitor's name. The inner %v error carries the actual cause — typically a bad bindPort, missing secretKey for STCP, or an unknown visitor type.

Source

Thrown at pkg/config/v1/validation/client.go:216

	validator := NewConfigValidator(unsafeFeatures)
	var warnings Warning
	if c != nil {
		warning, err := validator.ValidateClientCommonConfig(c)
		warnings = AppendError(warnings, warning)
		if err != nil {
			return warnings, err
		}
	}

	for _, c := range proxyCfgs {
		if err := ValidateProxyConfigurerForClient(c); err != nil {
			return warnings, fmt.Errorf("proxy %s: %v", c.GetBaseConfig().Name, err)
		}
	}

	for _, c := range visitorCfgs {
		if err := ValidateVisitorConfigurer(c); err != nil {
			return warnings, fmt.Errorf("visitor %s: %v", c.GetBaseConfig().Name, err)
		}
	}
	return warnings, nil
}

View on GitHub (pinned to 6c8a8d0a97)

Solutions

  1. Parse the inner error text after the visitor name to find the failing field
  2. Correct bindPort/serverName/secretKey per the visitor type's requirements
  3. Run `frpc verify -c frpc.toml` to iterate quickly without starting the client

Example fix

# before
[[visitors]]
name = "stcp-v"
type = "stcp"
serverName = "secret-ssh"
secretKey = ""
bindAddr = "127.0.0.1"
bindPort = 6000

# after
[[visitors]]
name = "stcp-v"
type = "stcp"
serverName = "secret-ssh"
secretKey = "shared-secret"
bindAddr = "127.0.0.1"
bindPort = 6000
Defensive patterns

Strategy: try-catch

Validate before calling

for _, v := range visitorCfgs {
    if err := validation.ValidateVisitorConfigurer(v); err != nil {
        // surface v.GetBaseConfig().Name + err before startup
    }
}

Try / catch

if err := validation.ValidateAllClientConfig(cc, proxies, visitors, uf); err != nil {
    if after, ok := strings.CutPrefix(err.Error(), "visitor "); ok {
        name, inner, _ := strings.Cut(after, ": ")
        // handle per-visitor failure keyed by name
    }
}

Prevention

When it happens

Trigger: A visitor block (stcp/sudp/xtcp visitors) failing per-type validation: e.g. stcp visitor without serverName, bindPort outside 0..65535, or missing secretKey. Validation stops at the first failing visitor.

Common situations: Client-side visitor config drift from server-side proxy config (secretKey mismatch shape); port already implied by another visitor; typos in visitor type field.

Related errors


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