fatedier/frp · error

failed to parse visitor %s, err: %v

Error message

failed to parse visitor %s, err: %v

What it means

Legacy ini loader counterpart of error 152: for a section with role = 'visitor', NewVisitorConfFromIni maps and validates it. Failures — missing required visitor fields (server_name, bind_port, secret_key for stcp/xtcp/sudp visitors), invalid ports, wrong type for a visitor — are wrapped with the section name.

Source

Thrown at pkg/config/legacy/client.go:279

			continue
		}

		roleType := section.Key("role").String()
		if roleType == "" {
			roleType = "server"
		}

		switch roleType {
		case "server":
			newConf, newErr := NewProxyConfFromIni(prefix, name, section)
			if newErr != nil {
				return nil, nil, fmt.Errorf("failed to parse proxy %s, err: %v", name, newErr)
			}
			proxyConfs[prefix+name] = newConf
		case "visitor":
			newConf, newErr := NewVisitorConfFromIni(prefix, name, section)
			if newErr != nil {
				return nil, nil, fmt.Errorf("failed to parse visitor %s, err: %v", name, newErr)
			}
			visitorConfs[prefix+name] = newConf
		default:
			return nil, nil, fmt.Errorf("proxy %s role should be 'server' or 'visitor'", name)
		}
	}
	return proxyConfs, visitorConfs, nil
}

func renderRangeProxyTemplates(f *ini.File, section *ini.Section) error {
	// Validation
	localPortStr := section.Key("local_port").String()
	remotePortStr := section.Key("remote_port").String()
	if localPortStr == "" || remotePortStr == "" {
		return fmt.Errorf("local_port or remote_port is empty")
	}

	localPorts, err := util.ParseRangeNumbers(localPortStr)

View on GitHub (pinned to 6c8a8d0a97)

Solutions

  1. Read the inner error to see which required key failed
  2. For stcp/xtcp visitors set: type, server_name (the exposed proxy's name), secret_key, bind_port, and role = visitor
  3. Ensure bind_port is a valid integer on the visitor host
  4. Confirm the exposing side and visitor share the same secret_key and server_name

Example fix

; before
[secret_visor]
role = visitor
type = stcp
server_name = secret-http
bind_port = 8080
; missing secret_key

; after
[secret_visor]
role = visitor
type = stcp
server_name = secret-http
secret_key = "abcdef"
bind_port = 8080
Defensive patterns

Strategy: validation

Validate before calling

required := []string{"server_name", "bind_port"}
if section.Key("type").String() != "http" { /* stcp/xtcp/sudp visitors also need secret_key */ }
for _, k := range required {
    if section.Key(k).String() == "" {
        return fmt.Errorf("visitor %s missing %s", section.Name(), k)
    }
}

Prevention

When it happens

Trigger: A [role = visitor] section for an stcp/xtcp/sudp proxy that omits server_name or secret_key, sets a non-numeric bind_port, or uses a type that does not support visitors (http/https/tcpmux).

Common situations: Setting up an stcp visitor and copying the server-side section without renaming keys; forgetting that visitors reference the exposing proxy by server_name, not proxy name; bind_port conflicts noted as invalid values.

Understand the failure class

Related errors


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