XX-net/XX-Net · warning

DNS s:%s query:%s fail t:%f

Error message

DNS s:%s query:%s fail t:%f

What it means

The DoH server returned a falsy/empty response object for the POSTed wire-format DNS query, so the code logs 'fail' with the elapsed time and returns an empty IP list. It indicates the HTTP layer completed without raising but produced no usable response (empty body, connection reset swallowed by the client, etc.).

Source

Thrown at code/default/smart_router/local/dns_query.py:578

        t0 = time.time()
        try:
            client = self.get_connection()

            if not url:
                url = self.server
            # xlog.debug("DoH use %s", url)

            d = DNSRecord(DNSHeader())
            d.add_question(DNSQuestion(domain, dns_type))
            data = d.pack()

            r = client.request("POST", url, headers={"accept": "application/dns-message",
                                                     "content-type": "application/dns-message"}, body=data)

            t2 = time.time()
            ips = []
            if not r:
                xlog.warn("DNS s:%s query:%s fail t:%f", self.server, domain,  t2 - t0)
                return ips

            p = DNSRecord.parse(r.text)

            self.connections.append([client, time.time()])

            for r in p.rr:
                ip = utils.to_bytes(str(r.rdata))
                if not utils.check_ip_valid(ip):
                    if ip == domain:
                        continue

                    ip_ips = self.query(ip, dns_type)
                    ips += ip_ips
                else:
                    ips.append(ip)

            xlog.debug("DNS %s %s return %s t:%f", self.protocol, domain, ips, t2 - t0)

View on GitHub (pinned to cfa5bc17b6)

Solutions

  1. Discard the pooled connection and retry once with a fresh connection
  2. Verify the DoH URL accepts POST with content-type application/dns-message (curl -H)
  3. Check for proxy interference on the connection
  4. Fall back to another resolver on empty result

Example fix

// before
r = client.request("POST", url, headers=..., body=data)
// after
r = client.request("POST", url, headers=..., body=data)
if not r:
    self.connections = []  # drop stale pooled connections
    r = client.request("POST", url, headers=..., body=data)
Defensive patterns

Strategy: retry

Try / catch

for attempt in range(2):
    ips = doh.query(domain)
    if ips:
        break
    doh.reset_connections()  # drop stale pooled sockets

Prevention

When it happens

Trigger: Calling query() where client.request('POST', url, ...) returns None or an empty response — e.g. the HTTP client failed silently, the connection was closed mid-request, or the server replied with an empty body.

Common situations: Flaky connection pool reuse after a server closes keep-alive connections, DoH endpoint behind a flaky proxy, server-side rate limiting returning empty responses.

Related errors


AI-assisted analysis of XX-net/XX-Net@cfa5bc17b6 (2026-08-27). Data as JSON: /api/errors/87cd6fb88b106680. Report an issue: GitHub.