XTLS/Xray-core · error
bridge tag is empty
Error message
bridge tag is empty
What it means
Reverse-proxy bridge constructor validation: a Bridge (the component on the controlled/inner side that relays connections from the Portal back to local services) requires a tag because that tag is how the reverse instance identifies and routes this bridge. NewBridge returns this error immediately when BridgeConfig.Tag is the empty string, before any worker starts.
Source
Thrown at app/reverse/bridge.go:31
"github.com/xtls/xray-core/features/routing"
"github.com/xtls/xray-core/transport"
"github.com/xtls/xray-core/transport/pipe"
"google.golang.org/protobuf/proto"
)
// Bridge is a component in reverse proxy, that relays connections from Portal to local address.
type Bridge struct {
dispatcher routing.Dispatcher
tag string
domain string
workers []*BridgeWorker
monitorTask *task.Periodic
}
// NewBridge creates a new Bridge instance.
func NewBridge(config *BridgeConfig, dispatcher routing.Dispatcher) (*Bridge, error) {
if config.Tag == "" {
return nil, errors.New("bridge tag is empty")
}
if config.Domain == "" {
return nil, errors.New("bridge domain is empty")
}
b := &Bridge{
dispatcher: dispatcher,
tag: config.Tag,
domain: config.Domain,
}
b.monitorTask = &task.Periodic{
Execute: b.monitor,
Interval: time.Second * 2,
}
return b, nil
}
func (b *Bridge) cleanup() {View on GitHub (pinned to 7d214f8b09)
Solutions
- Add a unique non-empty "tag" to every bridge entry in the reverse config.
- Check the bridge tag is not the same as any portal tag or outbound tag it may conflict with in routing.
- Validate the reverse config with xray run -test (or run -c config.json -test) before deploying.
Example fix
// before
"reverse": { "bridges": [ { "domain": "svc.internal" } ] }
// after
"reverse": { "bridges": [ { "tag": "bridge-1", "domain": "svc.internal" } ] } Defensive patterns
Strategy: validation
Validate before calling
// Before instance start
for _, b := range cfg.Reverse.Bridges {
if b.Tag == "" { return errors.New("reverse config: bridge tag is empty") }
} Type guard
func validBridgeConfig(b BridgeConfig) bool { return b.Tag != "" } Try / catch
// Constructor already validates; catch at feature creation and report path
if _, err := reverse.NewBridge(cfg, dispatcher); err != nil {
if strings.Contains(err.Error(), "bridge tag is empty") {
return fmt.Errorf("reverse.bridges[%d]: tag required", i)
}
return err
} Prevention
- Always emit tag+domain together when templating bridge entries
- Use config schema validation (JSON schema or -test) before deployment
- Keep reverse config pairs (portal/bridge) in one reviewed file
When it happens
Trigger: Building a reverse config (app/reverse) where a bridges[] entry omits the tag field (or sets it to ""), and the instance constructs the Bridge during feature startup.
Common situations: Hand-written or generated reverse configs missing the tag on a bridge entry; YAML/JSON field name typo ('Tag' vs 'tag') causing the field to stay empty; trimming a config down for testing and deleting the tag line. Startup fails with this error.
Related errors
- bridge domain is empty
- portal tag is empty
- portal domain is empty
- unknown action: {}
- rCode out of range: {}
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/247dcc6284397fa2.
Report an issue: GitHub.