XTLS/Xray-core · error · errors.Error
failed to build final rule
Error message
failed to build final rule
What it means
Thrown by freedom outbound's Init when one of the configured settings.finalRules entries cannot be compiled by buildFinalRule. The freedom handler iterates config.FinalRules at startup and aborts on the first rule that fails to parse (bad target address, unknown protocol, or empty rule fields). The underlying cause is attached via .Base(err).
Source
Thrown at proxy/freedom/freedom.go:214
return nil
}
func (h *Handler) applyFinalRules(network net.Network, address net.Address, port net.Port, defaultRule *FinalRule) RuleAction {
if rule := h.matchFinalRule(network, address, port, defaultRule); rule != nil {
return rule.action
}
return RuleAction_Allow
}
// Init initializes the Handler with necessary parameters.
func (h *Handler) Init(config *Config, pm policy.Manager) error {
h.config = config
h.policyManager = pm
h.finalRules = make([]*FinalRule, 0, len(config.FinalRules))
for _, rc := range config.FinalRules {
rule, err := buildFinalRule(rc)
if err != nil {
return errors.New("failed to build final rule").Base(err)
}
h.finalRules = append(h.finalRules, rule)
}
return nil
}
func (h *Handler) policy() policy.Session {
p := h.policyManager.ForLevel(h.config.UserLevel)
return p
}
func (h *Handler) blockDelay(rule *FinalRule) time.Duration {
min := uint64(30)
max := uint64(90)
if rule.blockDelay != nil {
min = rule.blockDelay.Min
max = rule.blockDelay.Max
}View on GitHub (pinned to 7d214f8b09)
Solutions
- Inspect the wrapped error (err) returned alongside the message — buildFinalRule names which rule field failed
- Validate every entry of settings.finalRules against the current Xray JSON schema (target, port, protocol/action fields)
- Run `xray run -test -c config.json` (or xlat) to lint the config before deploying
- Remove or fix the single offending rule; other rules are fine because iteration stops at the first failure
Example fix
// before
"settings": { "finalRules": [ { "target": "example.com", "port": "http" } ] }
// after
"settings": { "finalRules": [ { "target": "example.com", "port": "80,443", "action": "reject" } ] } Defensive patterns
Strategy: validation
Validate before calling
// before building the handler, dry-run the config
if err := freedomHandlerCreator; err != nil { ... }
// simplest: `xray run -test -c config.json` in CI catches buildFinalRule failures Try / catch
err := handler.Init(cfg, pm)
if err != nil {
if strings.Contains(err.Error(), "failed to build final rule") {
// unwrap err via errors.Unwrap to find the offending rule field
}
} Prevention
- Lint configs with `xray run -test` in CI
- Pin the finalRule schema to your Xray version
- Keep rule targets/ports syntactically simple CIDRs and ranges
When it happens
Trigger: Configuring an outbound with "protocol":"freedom" and a settings.finalRules array where an entry has an invalid/malformed target (e.g. bad CIDR, unparseable port range) or missing required fields; Init returns this before any traffic is processed.
Common situations: Hand-edited JSON config with typos in finalRules; migrating configs between Xray versions where the finalRule schema changed; copying example configs that use fields the current build does not support.
Related errors
- unsupported domain strategy: {}
- Invalid PacketsFrom
- invalid redirect address: {}
- invalid redirect port: {}
- invalid value for rand Length
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/525263f4f4c609cb.
Report an issue: GitHub.