fatedier/frp · error

proxy name [%s] is duplicated

Error message

proxy name [%s] is duplicated

What it means

validateNoDuplicateNames runs after loading all proxy/visitor configurers in the new (TOML/YAML/JSON) format. Because proxies and visitors are keyed by name in maps, duplicates would silently overwrite each other; this check rejects a duplicated proxy name with 'proxy name [<name>] is duplicated' so nothing is silently dropped.

Source

Thrown at pkg/config/load.go:432

	proxyCfgs := result.Proxies
	visitorCfgs := result.Visitors

	proxyCfgs, visitorCfgs = FilterClientConfigurers(result.Common, proxyCfgs, visitorCfgs)
	proxyCfgs = CompleteProxyConfigurers(proxyCfgs)
	visitorCfgs = CompleteVisitorConfigurers(visitorCfgs)
	return result.Common, proxyCfgs, visitorCfgs, result.IsLegacyFormat, nil
}

// validateNoDuplicateNames rejects proxies or visitors that share a name. They are
// keyed by name in the config sources, so a duplicate would otherwise be silently
// overwritten and never started, with no error or log.
func validateNoDuplicateNames(proxies []v1.ProxyConfigurer, visitors []v1.VisitorConfigurer) error {
	proxyNames := make(map[string]struct{}, len(proxies))
	for _, p := range proxies {
		name := p.GetBaseConfig().Name
		if _, ok := proxyNames[name]; ok {
			return fmt.Errorf("proxy name [%s] is duplicated", name)
		}
		proxyNames[name] = struct{}{}
	}

	visitorNames := make(map[string]struct{}, len(visitors))
	for _, v := range visitors {
		name := v.GetBaseConfig().Name
		if _, ok := visitorNames[name]; ok {
			return fmt.Errorf("visitor name [%s] is duplicated", name)
		}
		visitorNames[name] = struct{}{}
	}

	return nil
}

func CompleteProxyConfigurers(proxies []v1.ProxyConfigurer) []v1.ProxyConfigurer {
	proxyCfgs := proxies

View on GitHub (pinned to 6c8a8d0a97)

Solutions

  1. Find the duplicate name (the message includes it) and rename one of the entries
  2. If the duplicate comes from an include file, remove the copy from either the main file or the include
  3. grep the main file plus all includes for 'name = "<dup>"' to catch cross-file collisions

Example fix

# before
[[proxies]]
name = "web"
[[proxies]]
name = "web"

# after
[[proxies]]
name = "web-a"
[[proxies]]
name = "web-b"
Defensive patterns

Strategy: validation

Validate before calling

names := sets.New[string]()
for _, p := range allProxies { if names.Has(p.GetBaseConfig().Name) { return fmt.Errorf("duplicate proxy %s", p.GetBaseConfig().Name) }; names.Insert(p.GetBaseConfig().Name) }

Try / catch

if err := config.LoadClientConfig(path, strict); err != nil { if strings.Contains(err.Error(), "is duplicated") { /* extract name, dedupe sources, reload */ } }

Prevention

When it happens

Trigger: Two [[proxies]] entries in frpc.toml with the same name; the same proxy defined both in the main file and again in an included file (includes are merged before this check); names differing only by whitespace that normalize to equality.

Common situations: Copying a [[proxies]] block and forgetting to change name; per-host include files that re-declare a shared base proxy; merging configs from multiple teams.

Related errors


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