fatedier/frp · error

proxy %s role should be 'server' or 'visitor'

Error message

proxy %s role should be 'server' or 'visitor'

What it means

Legacy ini loader: each non-common, non-range section must declare role = server or role = visitor (defaulting to server when role is empty). Any other value — including typos — hits the default branch and abort config loading with this error.

Source

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

		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)
	if err != nil {
		return err
	}

View on GitHub (pinned to 6c8a8d0a97)

Solutions

  1. Set role = server for exposing proxies or role = visitor for visitor sections, exact lowercase
  2. Remove the role key entirely for plain proxies (server is the default)
  3. Scan the config for stray whitespace or quotes around the role value

Example fix

; before
[ssh]
role = Server

; after (or just drop the key)
[ssh]
role = server
Defensive patterns

Strategy: validation

Validate before calling

role := section.Key("role").String()
if role != "" && role != "server" && role != "visitor" {
    return fmt.Errorf("section %s: role must be 'server' or 'visitor'", section.Name())
}

Type guard

func isValidRole(role string) bool { return role == "" || role == "server" || role == "visitor" }

Prevention

When it happens

Trigger: A section with role = 'Server' (capitalized), 'srv', 'visit0r', or any string other than exactly 'server' or 'visitor'. Note the value is not trimmed beyond ini parsing, so trailing spaces also fail.

Common situations: Users upgrading from configs where role did not exist and guessing the value; case or spelling mistakes; copy-paste from docs of a different frp version that used different role names.

Related errors


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