XTLS/Xray-core · error
AddRule: config type error
Error message
AddRule: config type error
What it means
AddRule expects the TypedMessage payload to decode to the router's *Config type (a full routing config). Any other message type is rejected because rule addition is implemented as a partial config reload.
Source
Thrown at app/router/router.go:120
if err != nil {
return nil, err
}
if rule.Webhook != nil {
rule.Webhook.Fire(originalCtx, tag)
}
return &Route{Context: ctx, outboundTag: tag, ruleTag: rule.RuleTag}, nil
}
// AddRule implements routing.Router.
func (r *Router) AddRule(config *serial.TypedMessage, shouldAppend bool) error {
inst, err := config.GetInstance()
if err != nil {
return err
}
if c, ok := inst.(*Config); ok {
return r.ReloadRules(c, shouldAppend)
}
return errors.New("AddRule: config type error")
}
func (r *Router) ReloadRules(config *Config, shouldAppend bool) error {
r.mu.Lock()
defer r.mu.Unlock()
if !shouldAppend {
for _, rule := range r.rules {
if rule.Webhook != nil {
rule.Webhook.Close()
}
}
r.balancers = make(map[string]*Balancer, len(config.BalancingRule))
r.rules = make([]*Rule, 0, len(config.Rule))
}
for _, rule := range config.BalancingRule {
_, found := r.balancers[rule.Tag]
if found {View on GitHub (pinned to 7d214f8b09)
Solutions
- Wrap the rule inside a routing Config message: TypedMessage of app.router.Config containing the new rule
- Use a helper (serial.ToTypedMessage(&router.Config{Rule: [...]})) to build the payload
- Verify the @type string matches the registered Config message
Example fix
// before
msg := serial.ToTypedMessage(&router.Rule{}) // wrong type
router.AddRule(msg, true) // config type error
// after
msg := serial.ToTypedMessage(&router.Config{Rule: []*router.RoutingRule{rule}})
router.AddRule(msg, true) Defensive patterns
Strategy: type-guard
Validate before calling
inst, err := msg.GetInstance()
if err != nil { return err }
if _, ok := inst.(*router.Config); !ok {
return fmt.Errorf("AddRule expects app.router.Config, got %T", inst)
} Type guard
func isRouterConfig(msg *serial.TypedMessage) bool {
i, err := msg.GetInstance()
return err == nil && isConfigType(i)
}
func isConfigType(i interface{}) bool { _, ok := i.(*router.Config); return ok } Prevention
- Build AddRule payloads with serial.ToTypedMessage(&router.Config{...})
- Encapsulate gRPC call construction in one client module
- Unit-test payload types against the server assertion
When it happens
Trigger: Calling AddRule with a serial.TypedMessage whose @type resolves to something other than app.router.Config (e.g. a raw rule message or a config from a different module).
Common situations: Clients assuming AddRule takes a single rule object; cross-version protobuf type URLs; hand-built TypedMessage with wrong type URL.
Related errors
- unsupported router implementation
- unable to get logger instance
- failed to close logger
- failed to start logger
- unable to select outbounds
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/8b016d4f7010e850.
Report an issue: GitHub.