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

  1. Add a unique non-empty "tag" to every bridge entry in the reverse config.
  2. Check the bridge tag is not the same as any portal tag or outbound tag it may conflict with in routing.
  3. 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

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


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