XTLS/Xray-core · error
invalid resolver + r
Error message
invalid resolver + r
What it means
Thrown by Xdns.Build() for every entry in the 'resolvers' list that does not contain the '+udp://' marker. Resolvers must be encoded in a compound form like 'IP+udp://domain' — the +udp:// part selects UDP transport and carries the DNS name. Any other shape (bare IP, plain URL, tcp scheme) is rejected.
Source
Thrown at infra/conf/transport_finalmask.go:713
type Xdns struct {
Domain json.RawMessage `json:"domain"`
Domains []string `json:"domains"`
Resolvers []string `json:"resolvers"`
}
func (c *Xdns) Build() (proto.Message, error) {
if c.Domain != nil {
return nil, errors.PrintRemovedFeatureError("domain", "domains(server) & resolvers(client)")
}
if len(c.Domains) == 0 && len(c.Resolvers) == 0 {
return nil, errors.New("empty domains & empty resolvers")
}
for _, r := range c.Resolvers {
if !strings.Contains(r, "+udp://") {
return nil, errors.New("invalid resolver ", r)
}
}
return &xdns.Config{
Domains: c.Domains,
Resolvers: c.Resolvers,
}, nil
}
type XMC struct {
Hostname string `json:"hostname"`
Profiles []XMCProfile `json:"profiles"`
Password string `json:"password"`
}
type XMCProfile struct {
// Resolve the UUID by username, then request the session profile with
// unsigned=false. Client and server must use the same signed profile.View on GitHub (pinned to 7d214f8b09)
Solutions
- Rewrite each resolver as '<source-ip>+udp://<domain>', e.g. "1.1.1.1+udp://cloudflare-dns.com".
- Verify the '+' is present and the marker is exactly '+udp://'.
- If you only need domain routing, move entries to 'domains' instead.
Example fix
// before "resolvers": ["8.8.8.8"] // after "resolvers": ["8.8.8.8+udp://dns.google"]
Defensive patterns
Strategy: validation
Validate before calling
for _, r := range resolvers {
if !strings.Contains(r, "+udp://") {
return fmt.Errorf("resolver %q must look like '<ip>+udp://<domain>'", r)
}
} Prevention
- Standardize resolver strings as '<source-ip>+udp://<resolver-domain>' in templates.
- Reject bare IPs at generator time, not at core start.
- Add a unit test asserting every emitted resolver contains '+udp://'.
When it happens
Trigger: Writing "8.8.8.8" or "https://dns.google" or "1.1.1.1+tcp://example.com" in the resolvers array triggers this at Build(). Only strings containing '+udp://' pass, e.g. "1.1.1.1+udp://dns.google".
Common situations: Assuming resolvers take plain host:port DNS addresses; migrating from another client that accepts bare IPs; typos like 'udp://' without the '+' or '+udp:/'.
Related errors
- unknown action: {}
- rCode out of range: {}
- unknown nonIPQuery: {}
- empty domains & empty resolvers
- bridge tag is empty
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/f78775481a8078f5.
Report an issue: GitHub.