XTLS/Xray-core · error
VLESS reverse: "tag" can't be empty
Error message
VLESS reverse: "tag" can't be empty
What it means
Thrown by VLessReverseConfig.Build() when building a VLESS reverse proxy entry whose "tag" field is empty. The tag is the routing identifier that outbound traffic uses to reach the reverse tunnel, so an empty tag makes the entry unroutable and is rejected immediately.
Source
Thrown at infra/conf/vless.go:224
if fb.Type == "" {
return nil, errors.New(`VLESS fallbacks: please fill in a valid value for every "dest"`)
}
if fb.Xver > 2 {
return nil, errors.New(`VLESS fallbacks: invalid PROXY protocol version, "xver" only accepts 0, 1, 2`)
}
}
return config, nil
}
type VLessReverseConfig struct {
Tag string `json:"tag"`
Sniffing *SniffingConfig `json:"sniffing"`
}
func (c *VLessReverseConfig) Build() (*vless.Reverse, error) {
if c.Tag == "" {
return nil, errors.New(`VLESS reverse: "tag" can't be empty`)
}
r := &vless.Reverse{
Tag: c.Tag,
}
if c.Sniffing != nil {
sc, err := c.Sniffing.Build()
if err != nil {
return nil, errors.New(`VLESS reverse: invalid "sniffing" config`).Base(err)
}
r.Sniffing = sc
}
return r, nil
}
type VLessOutboundVnext struct {
Address *Address `json:"address"`
Port uint16 `json:"port"`
Users []json.RawMessage `json:"users"`View on GitHub (pinned to 7d214f8b09)
Solutions
- Add a non-empty "tag" to the reverse object, e.g. "reverse":{"tag":"myreverse"}
- Ensure the tag matches the tag used in routing rules / the server side bridge configuration
- Check for typos in the key name — it must be exactly "tag"
Example fix
// before
"reverse": { "sniffing": { "enabled": true } }
// after
"reverse": { "tag": "reverse_tunnel", "sniffing": { "enabled": true } } Defensive patterns
Strategy: validation
Validate before calling
func validateReverseTag(cfg map[string]any) error {
outbounds, _ := cfg["outbounds"].([]any)
for _, ob := range outbounds {
m, _ := ob.(map[string]any)
settings, _ := m["settings"].(map[string]any)
if rev, ok := settings["reverse"].(map[string]any); ok {
if t, _ := rev["tag"].(string); t == "" {
return fmt.Errorf("outbound %v: reverse.tag is empty", m["tag"])
}
}
}
return nil
} Type guard
func reverseHasTag(rev any) bool {
m, ok := rev.(map[string]any)
if !ok { return false }
t, _ := m["tag"].(string)
return t != ""
} Prevention
- Whenever you add "reverse", immediately add its "tag" in the same edit
- Reuse one naming scheme for reverse tags and reference it in routing rules
- Lint outbounds for non-empty reverse.tag before deploy
When it happens
Trigger: Simplified outbound config with "reverse":{} (no "tag" key), or reverse: {"tag":""}. The error surfaces when VLessOutboundConfig.Build() calls c.Reverse.Build().
Common situations: Enabling the reverse feature for the first time and forgetting the tag; trimming down a config example too aggressively; tag key misspelled (e.g. "name" or "outboundTag").
Related errors
- VLESS reverse: invalid "sniffing" config
- Proxy tag is not set.
- VLESS fallbacks: "path" must be empty or start with "/"
- VLESS fallbacks: please fill in a valid value for every "des
- VLESS fallbacks: invalid PROXY protocol version, "xver" only
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/b54d8e2edf60f639.
Report an issue: GitHub.