{"record":{"id":"f68879f5bf63e7ae","repo":"XTLS/Xray-core","slug":"invalid-dns-hosts","errorCode":null,"errorMessage":"invalid DNS hosts","messagePattern":"invalid DNS hosts","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"infra/conf/dns.go","lineNumber":250,"sourceCode":"\treturn &dns.Config_HostMapping{\n\t\tIp: ips,\n\t}\n}\n\n// MarshalJSON implements encoding/json.Marshaler.MarshalJSON\nfunc (m *HostsWrapper) MarshalJSON() ([]byte, error) {\n\treturn json.Marshal(m.Hosts)\n}\n\n// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON\nfunc (m *HostsWrapper) UnmarshalJSON(data []byte) error {\n\thosts := make(map[string]*HostAddress)\n\terr := json.Unmarshal(data, &hosts)\n\tif err == nil {\n\t\tm.Hosts = hosts\n\t\treturn nil\n\t}\n\treturn errors.New(\"invalid DNS hosts\").Base(err)\n}\n\n// Build implements Buildable\nfunc (m *HostsWrapper) Build() ([]*dns.Config_HostMapping, error) {\n\tmappings := make([]*dns.Config_HostMapping, 0, len(m.Hosts))\n\tfor rule, addrs := range m.Hosts {\n\t\tmapping := newHostMapping(addrs)\n\t\trule, err := geodata.ParseDomainRule(rule, geodata.Domain_Full)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tmapping.Domain = rule\n\t\tmappings = append(mappings, mapping)\n\t}\n\treturn mappings, nil\n}\n\n// Build implements Buildable","sourceCodeStart":232,"sourceCodeEnd":268,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/infra/conf/dns.go#L232-L268","documentation":"Thrown by HostsWrapper.UnmarshalJSON in infra/conf/dns.go when the dns.hosts value as a whole is not a JSON object mapping hostnames to HostAddress values. json.Unmarshal into map[string]*HostAddress must succeed; otherwise the error is returned with the json error chained via .Base(err).","triggerScenarios":"\"hosts\": [\"example.com\"], \"hosts\": \"example.com\", \"hosts\": 123, or a JSON object whose keys are fine but syntax errors exist (missing quotes, trailing comma) making the map unmarshal fail.","commonSituations":"Treating hosts like an array of domain strings; YAML-to-JSON converters emitting null for an empty hosts map in some edge cases; per-entry problems surface as error 254 instead, so this one indicates a structural (map-level) problem.","solutions":["Make hosts a flat object: \"hosts\": {\"domain.example\": \"1.2.3.4\"}","Run the config through a JSON validator to catch structural syntax errors","Inspect the chained base error for the exact JSON position"],"exampleFix":"// before\n\"hosts\": [\"example.com\"]\n\n// after\n\"hosts\": {\"example.com\": \"1.2.3.4\"}","handlingStrategy":"type-guard","validationCode":"func validateHostsShape(v any) error {\n    m, ok := v.(map[string]any)\n    if !ok {\n        return errors.New(\"hosts must be an object mapping domains to addresses\")\n    }\n    for k, val := range m {\n        if err := isHostAddressValue(val); err != nil {\n            return fmt.Errorf(\"hosts[%s]: %w\", k, err)\n        }\n    }\n    return nil\n}","typeGuard":"func isHostsMap(v any) bool {\n    m, ok := v.(map[string]any)\n    if !ok {\n        return false\n    }\n    for _, val := range m {\n        if !isHostAddress(val) {\n            return false\n        }\n    }\n    return true\n}","tryCatchPattern":"if err := json.Unmarshal(data, &hw); err != nil {\n    if strings.Contains(err.Error(), \"invalid DNS hosts\") {\n        return fmt.Errorf(\"dns.hosts must be an object like {\"example.com\": \"1.2.3.4\"}\")\n    }\n    return err\n}","preventionTips":["hosts is a flat map, not an array","Validate JSON structure with jq or a linter before loading"],"tags":["config","dns","hosts","validation","xray"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}