{"record":{"id":"881f8a1eb79b8b3c","repo":"XX-net/XX-Net","slug":"dnsoverhttpsquery-query-fail-r","errorCode":null,"errorMessage":"DNSOverHttpsQuery query fail:%r","messagePattern":"DNSOverHttpsQuery query fail:%r","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"code/default/smart_router/local/dns_query.py","lineNumber":556,"sourceCode":"            r = client.request(\"GET\", url, headers={\"accept\": \"application/dns-json\"})\n            t2 = time.time()\n            ips = []\n            if not r:\n                xlog.warn(\"DNS server:%s domain:%s fail t:%f\", self.server, domain,  t2 - t0)\n                return ips\n\n            t = utils.to_str(r.text)\n\n            data = json.loads(t)\n            for answer in data[\"Answer\"]:\n                ips.append(answer[\"data\"])\n\n            self.connections.append([client, time.time()])\n\n            xlog.debug(\"DNS server:%s query:%s return %s t:%f\", self.server, domain, ips, t2 - t0)\n            return ips\n        except Exception as e:\n            xlog.warn(\"DNSOverHttpsQuery query fail:%r\", e)\n            return []\n\n    def query(self, domain, dns_type=1, url=None):\n        t0 = time.time()\n        try:\n            client = self.get_connection()\n\n            if not url:\n                url = self.server\n            # xlog.debug(\"DoH use %s\", url)\n\n            d = DNSRecord(DNSHeader())\n            d.add_question(DNSQuestion(domain, dns_type))\n            data = d.pack()\n\n            r = client.request(\"POST\", url, headers={\"accept\": \"application/dns-message\",\n                                                     \"content-type\": \"application/dns-message\"}, body=data)\n","sourceCodeStart":538,"sourceCodeEnd":574,"githubUrl":"https://github.com/XX-net/XX-Net/blob/cfa5bc17b67676e467f37ec50766127e0ab5f0aa/code/default/smart_router/local/dns_query.py#L538-L574","documentation":"A DNS-over-HTTPS query failed with an unexpected exception inside query_json. The method wraps the whole JSON DoH request/parse cycle in a try/except and logs the exception %r, returning an empty IP list instead of raising. Typical underlying causes are network timeouts, TLS errors, or malformed JSON responses from the DoH server.","triggerScenarios":"Calling DNSOverHttpsQuery.query_json() when the HTTPS request to the DoH endpoint raises (connection refused, timeout, SSL verification failure), or when the response body cannot be parsed as the expected JSON DNS answer.","commonSituations":"DoH server URL misconfigured or unreachable, proxy blocking the DoH endpoint, server returning an HTML error page instead of DNS JSON, or Python 2/3 bytes/str issues when parsing r.text.","solutions":["Check network reachability of the DoH server URL (curl it) and verify it returns application/dns-json responses","Inspect the logged exception %r to identify timeout vs TLS vs parse errors","Retry with a different DoH provider or fall back to plain UDP DNS","Increase client timeout / reuse connections in self.connections pool"],"exampleFix":"// before\nips = doh.query_json(domain)\n// after\nips = doh.query_json(domain)\nif not ips:\n    ips = udp_resolver.query(domain)  # fallback resolver","handlingStrategy":"fallback","validationCode":"def has_doh_endpoint(url):\n    return url.startswith(\"https://\") and \"/dns\" in url","typeGuard":null,"tryCatchPattern":"try:\n    ips = doh.query_json(domain)\nexcept Exception:\n    ips = []\nif not ips:\n    ips = fallback_resolver.query(domain)","preventionTips":["Configure multiple DoH/UDP resolvers and fall back on empty results","Monitor the warn log to detect a dead DoH endpoint early","Validate the DoH URL at startup with a test query"],"tags":["dns","doh","network","https"],"backgroundTag":"dns-resolution-failed","analyzedSha":"cfa5bc17b67676e467f37ec50766127e0ab5f0aa","analyzedAt":"2026-08-27T19:28:28.225Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}