XTLS/Xray-core · error
existing tag found: ${tag}
Error message
existing tag found: ${tag} What it means
Configuration/startup validation error from the outbound manager: addHandler refuses to register a second handler with the same non-empty tag. Tags are the lookup key for routing rules, balancers, and proxySettings chaining, so duplicates would make resolution ambiguous; the manager returns this error instead of overwriting.
Source
Thrown at app/proxyman/outbound/outbound.go:116
}
return nil
}
// AddHandler implements outbound.Manager.
func (m *Manager) AddHandler(ctx context.Context, handler outbound.Handler) error {
m.access.Lock()
defer m.access.Unlock()
m.tagsCache = &sync.Map{}
if m.defaultHandler == nil {
m.defaultHandler = handler
}
tag := handler.Tag()
if len(tag) > 0 {
if _, found := m.taggedHandler[tag]; found {
return errors.New("existing tag found: " + tag)
}
m.taggedHandler[tag] = handler
} else {
m.untaggedHandlers = append(m.untaggedHandlers, handler)
}
if m.running {
return handler.Start()
}
return nil
}
// RemoveHandler implements outbound.Manager.
func (m *Manager) RemoveHandler(ctx context.Context, tag string) error {
if tag == "" {
return common.ErrNoClue
}View on GitHub (pinned to 7d214f8b09)
Solutions
- Search the outbounds array for duplicate "tag" values and rename one of them to a unique string.
- Update any references (routing rules, balancer selectors, proxySettings.tag) to the new name.
- When merging configs, namespace tags with a prefix per profile (e.g. 'home-vless', 'office-trojan').
Example fix
// before
[{ "tag": "proxy", "protocol": "vless", ... },
{ "tag": "proxy", "protocol": "trojan", ... }]
// after
[{ "tag": "vless-out", "protocol": "vless", ... },
{ "tag": "trojan-out", "protocol": "trojan", ... }] Defensive patterns
Strategy: validation
Validate before calling
// Pre-register check: unique, non-empty tags
seen := map[string]bool{}
for _, ob := range cfg.Outbounds {
if ob.Tag == "" { continue }
if seen[ob.Tag] { return fmt.Errorf("duplicate outbound tag %q", ob.Tag) }
seen[ob.Tag] = true
} Type guard
func validateUniqueTags(outbounds []OutboundConfig) error {
seen := map[string]struct{}
for _, o := range outbounds {
if o.Tag == "" { continue }
if _, dup := seen[o.Tag]; dup { return fmt.Errorf("duplicate tag %q", o.Tag) }
seen[o.Tag] = struct{}{}
}
return nil
} Try / catch
// Registration-side: detect and report clearly at startup
if err := ohm.AddHandler(ctx, h); err != nil {
if strings.Contains(err.Error(), "existing tag found") {
return fmt.Errorf("config: tag %q defined twice; rename one", h.Tag())
}
return err
} Prevention
- Namespace tags per profile when merging configs (home-, work-)
- Add a config-lint step to CI for duplicate tags
- Avoid empty tags unless you intentionally want untagged handlers
When it happens
Trigger: Calling Manager.addHandler (via outbound handler creation at instance start) with a handler whose Tag() is already a key in m.taggedHandler — i.e. two outbounds in the JSON config sharing the same "tag" string. Handlers with empty tags go to untaggedHandlers and never collide.
Common situations: Copy-pasting an outbound block and forgetting to change its tag; GUI clients (v2rayN-style) generating duplicated tags when importing profiles; merging configs that each define a common tag like 'proxy' or 'direct'. The instance fails to start with this error.
Related errors
- failed to get outbound handler with tag: ${tag}
- unsupported domain strategy: {}
- invalid redirect address: {}
- invalid redirect port: {}
- SOCKS servers: "users" should have one member at most. Multi
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/4c142905a168998f.
Report an issue: GitHub.