{"record":{"id":"525263f4f4c609cb","repo":"XTLS/Xray-core","slug":"failed-to-build-final-rule","errorCode":null,"errorMessage":"failed to build final rule","messagePattern":"failed to build final rule","errorType":"validation","errorClass":"errors.Error","httpStatus":null,"severity":"error","filePath":"proxy/freedom/freedom.go","lineNumber":214,"sourceCode":"\treturn nil\n}\n\nfunc (h *Handler) applyFinalRules(network net.Network, address net.Address, port net.Port, defaultRule *FinalRule) RuleAction {\n\tif rule := h.matchFinalRule(network, address, port, defaultRule); rule != nil {\n\t\treturn rule.action\n\t}\n\treturn RuleAction_Allow\n}\n\n// Init initializes the Handler with necessary parameters.\nfunc (h *Handler) Init(config *Config, pm policy.Manager) error {\n\th.config = config\n\th.policyManager = pm\n\th.finalRules = make([]*FinalRule, 0, len(config.FinalRules))\n\tfor _, rc := range config.FinalRules {\n\t\trule, err := buildFinalRule(rc)\n\t\tif err != nil {\n\t\t\treturn errors.New(\"failed to build final rule\").Base(err)\n\t\t}\n\t\th.finalRules = append(h.finalRules, rule)\n\t}\n\treturn nil\n}\n\nfunc (h *Handler) policy() policy.Session {\n\tp := h.policyManager.ForLevel(h.config.UserLevel)\n\treturn p\n}\n\nfunc (h *Handler) blockDelay(rule *FinalRule) time.Duration {\n\tmin := uint64(30)\n\tmax := uint64(90)\n\tif rule.blockDelay != nil {\n\t\tmin = rule.blockDelay.Min\n\t\tmax = rule.blockDelay.Max\n\t}","sourceCodeStart":196,"sourceCodeEnd":232,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/proxy/freedom/freedom.go#L196-L232","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\n\"settings\": { \"finalRules\": [ { \"target\": \"example.com\", \"port\": \"http\" } ] }\n// after\n\"settings\": { \"finalRules\": [ { \"target\": \"example.com\", \"port\": \"80,443\", \"action\": \"reject\" } ] }","handlingStrategy":"validation","validationCode":"// before building the handler, dry-run the config\nif err := freedomHandlerCreator; err != nil { ... }\n// simplest: `xray run -test -c config.json` in CI catches buildFinalRule failures","typeGuard":null,"tryCatchPattern":"err := handler.Init(cfg, pm)\nif err != nil {\n  if strings.Contains(err.Error(), \"failed to build final rule\") {\n    // unwrap err via errors.Unwrap to find the offending rule field\n  }\n}","preventionTips":["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"],"tags":["freedom","config","validation","xray"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}