{"record":{"id":"7d2b08306ed74f23","repo":"XTLS/Xray-core","slug":"invalid-address-7d2b08","errorCode":null,"errorMessage":"invalid address","messagePattern":"invalid address","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"infra/conf/dns.go","lineNumber":202,"sourceCode":"\t\t\treturn json.Marshal(h.addr)\n\t\t} else if h.addrs != nil {\n\t\t\treturn json.Marshal(h.addrs)\n\t\t}\n\t}\n\treturn nil, errors.New(\"unexpected config state\")\n}\n\n// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON\nfunc (h *HostAddress) UnmarshalJSON(data []byte) error {\n\taddr := new(Address)\n\tvar addrs []*Address\n\tswitch {\n\tcase json.Unmarshal(data, &addr) == nil:\n\t\th.addr = addr\n\tcase json.Unmarshal(data, &addrs) == nil:\n\t\th.addrs = addrs\n\tdefault:\n\t\treturn errors.New(\"invalid address\")\n\t}\n\treturn nil\n}\n\ntype HostsWrapper struct {\n\tHosts map[string]*HostAddress\n}\n\nfunc newHostMapping(ha *HostAddress) *dns.Config_HostMapping {\n\tif ha.addr != nil {\n\t\tif ha.addr.Family().IsDomain() {\n\t\t\treturn &dns.Config_HostMapping{\n\t\t\t\tProxiedDomain: ha.addr.Domain(),\n\t\t\t}\n\t\t}\n\t\treturn &dns.Config_HostMapping{\n\t\t\tIp: [][]byte{ha.addr.IP()},\n\t\t}","sourceCodeStart":184,"sourceCodeEnd":220,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/infra/conf/dns.go#L184-L220","documentation":"Thrown by HostAddress.UnmarshalJSON in infra/conf/dns.go when a dns.hosts value is neither a single address string (Address unmarshal) nor an array of address strings. Hosts entries accept \"domain\": \"ip\" or \"domain\": [\"ip1\",\"ip2\"]; any other JSON type hits the default branch.","triggerScenarios":"\"hosts\": {\"example.com\": 12345}, {\"example.com\": {\"ip\":\"1.2.3.4\"}}, or {\"example.com\": true}. Also nested arrays or mixed arrays where Address unmarshal of the array form fails.","commonSituations":"Adding a port to a hosts entry (\"example.com\": \"1.2.3.4:80\" parses but later address parsing of the combined string produces a domain-family address — different failure); putting objects meant for other DNS fields under hosts.","solutions":["Map each host to a string IP or domain: \"hosts\": {\"example.com\": \"1.2.3.4\"}","For multiple targets use an array of strings: \"hosts\": {\"example.com\": [\"1.2.3.4\", \"5.6.7.8\"]}","Do not include ports or nested objects in hosts values"],"exampleFix":"// before\n\"hosts\": {\"example.com\": {\"ip\": \"1.2.3.4\"}}\n\n// after\n\"hosts\": {\"example.com\": \"1.2.3.4\"}","handlingStrategy":"type-guard","validationCode":"func isHostAddressValue(v any) error {\n    switch t := v.(type) {\n    case string:\n        return nil\n    case []any:\n        for _, e := range t {\n            if _, ok := e.(string); !ok {\n                return fmt.Errorf(\"host array entry %v is not a string\", e)\n            }\n        }\n        return nil\n    }\n    return errors.New(\"hosts value must be a string or array of strings\")\n}","typeGuard":"func isHostAddress(v any) bool {\n    if _, ok := v.(string); ok {\n        return true\n    }\n    arr, ok := v.([]any)\n    if !ok {\n        return false\n    }\n    for _, e := range arr {\n        if _, isStr := e.(string); !isStr {\n            return false\n        }\n    }\n    return true\n}","tryCatchPattern":"if err := json.Unmarshal(data, &ha); err != nil {\n    if strings.Contains(err.Error(), \"invalid address\") {\n        return fmt.Errorf(\"hosts value %s must be \"ip\" or [\"ip1\",\"ip2\"]\", data)\n    }\n    return err\n}","preventionTips":["Hosts values are plain strings or string arrays only","No ports, no nested objects in hosts entries"],"tags":["config","dns","hosts","validation","xray"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}