XTLS/Xray-core · error

unknown action: {}

Error message

unknown action: {}

What it means

Thrown while building a DNS rule in an Xray DNS outbound/proxy config: the rule's 'action' string did not match any of the supported keywords. The switch in DNSRuleConfig.Build() only accepts 'direct', 'drop', 'return', and 'hijack' (case-insensitive), and any other value falls into the default branch. This is a config parse/build error surfaced at startup when the JSON config is compiled into protobuf.

Source

Thrown at infra/conf/dns_proxy.go:33

	QType  *PortList   `json:"qType"`
	Domain *StringList `json:"domain"`
	RCode  uint32      `json:"rCode"`
}

func (c *DNSOutboundRuleConfig) Build() (*dns.DNSRuleConfig, error) {
	rule := &dns.DNSRuleConfig{}

	switch strings.ToLower(c.Action) {
	case "direct":
		rule.Action = dns.RuleAction_Direct
	case "drop":
		rule.Action = dns.RuleAction_Drop
	case "return":
		rule.Action = dns.RuleAction_Return
	case "hijack":
		rule.Action = dns.RuleAction_Hijack
	default:
		return nil, errors.New("unknown action: ", c.Action)
	}

	if c.QType != nil {
		for _, r := range c.QType.Range {
			for qType := r.From; qType <= r.To; qType++ {
				rule.QType = append(rule.QType, int32(qType))
			}
		}
	}

	if c.Domain != nil {
		rules, err := geodata.ParseDomainRules(*c.Domain, geodata.Domain_Substr)
		if err != nil {
			return nil, err
		}
		rule.Domain = rules
	}

View on GitHub (pinned to 7d214f8b09)

Solutions

  1. Set "action" to one of exactly: "direct", "drop", "return", "hijack" (case-insensitive).
  2. For old 'reject' behavior use "return" with "rcode" (e.g. rcode 5 = REFUSED) instead of a reject action.
  3. If you want the query sent through normally, use "direct".
  4. Validate all action strings against the accepted set before feeding the config to Xray.

Example fix

// before
{"type": "field", "action": "reject", "qType": [255]}

// after
{"type": "field", "action": "return", "rcode": 5, "qType": [255]}
Defensive patterns

Strategy: validation

Validate before calling

var validDNSActions = map[string]bool{"direct": true, "drop": true, "return": true, "hijack": true}

func validAction(a string) bool { return validDNSActions[strings.ToLower(strings.TrimSpace(a))] }

// before calling config Build / starting Xray:
for _, r := range dnsOutbound.Rules {
    if !validAction(r.Action) {
        log.Fatalf("invalid DNS rule action %q (want direct|drop|return|hijack)", r.Action)
    }
}

Prevention

When it happens

Trigger: A JSON DNS rule object whose "action" field is misspelled (e.g. "block", "reject", "allow", "Drop " with trailing space is OK since strings.ToLower is used but "dropp" is not) or uses a synonym that the engine does not know. Calling Build() on a DNSRuleConfig with an unrecognized Action string always returns this error.

Common situations: Migrating from older Xray/V2Ray DNS configs where 'reject' semantics were expressed differently; copy-pasting rule examples from other projects (sing-box, AdGuard) that use different action names; typos in hand-written JSON.

Related errors


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