XTLS/Xray-core · error
bridge domain is empty
Error message
bridge domain is empty
What it means
Reverse-proxy bridge constructor validation, the sibling of the tag check: each Bridge must advertise the domain it serves, because the portal side matches connection targets against that domain to decide which bridge a connection belongs to. NewBridge returns this error when BridgeConfig.Domain is empty.
Source
Thrown at app/reverse/bridge.go:34
"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() {
var activeWorkers []*BridgeWorker
for _, w := range b.workers {View on GitHub (pinned to 7d214f8b09)
Solutions
- Set a non-empty "domain" on the bridge entry; it must equal the domain the portal side uses for this bridge.
- Ensure the same domain appears in the matching portal config so isDomain matching on the portal side works.
- Prefer a dedicated reserved domain (e.g. *.reverse.internal) to avoid clashing with real DNS names.
Example fix
// before
"reverse": { "bridges": [ { "tag": "bridge-1" } ] }
// after
"reverse": { "bridges": [ { "tag": "bridge-1", "domain": "svc.reverse.internal" } ] } Defensive patterns
Strategy: validation
Validate before calling
for _, b := range cfg.Reverse.Bridges {
if b.Domain == "" { return errors.New("reverse config: bridge domain is empty") }
} Type guard
func validBridgeDomain(b BridgeConfig) bool { return b.Domain != "" } Try / catch
if _, err := reverse.NewBridge(cfg, dispatcher); err != nil {
if strings.Contains(err.Error(), "bridge domain is empty") {
return fmt.Errorf("reverse.bridges[%d]: domain required", i)
}
return err
} Prevention
- Template bridges as {tag, domain} units so one is never emitted without the other
- Use a reserved internal suffix for reverse domains
- Validate config with xray run -test in deployment scripts
When it happens
Trigger: A reverse config bridges[] entry with a missing or empty "domain" field; the check fires after the tag check passes, during Bridge construction at instance start.
Common situations: Omitting the domain when writing a reverse tunnel config; using an IP or port string where a domain is expected and accidentally clearing the field; converting configs between formats and dropping the domain key. Startup aborts.
Related errors
- bridge tag 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/865e407f98946e05.
Report an issue: GitHub.