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

  1. Search the outbounds array for duplicate "tag" values and rename one of them to a unique string.
  2. Update any references (routing rules, balancer selectors, proxySettings.tag) to the new name.
  3. 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

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


AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15). Data as JSON: /api/errors/4c142905a168998f. Report an issue: GitHub.