XX-net/XX-Net · warning

query_dns_from_xxnet %s json:%s parse fail:%s

Error message

query_dns_from_xxnet %s json:%s parse fail:%s

What it means

query_dns_from_xxnet() got a 200 response but failed while parsing: it either couldn't json-decode the body or couldn't split the 'ip|cn' entries in the returned list. The warning includes the domain, the raw content, and the parse exception, then returns an empty IP list.

Source

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

    if isinstance(content, memoryview):
        content = content.tobytes()

    content = utils.to_str(content)

    try:
        rs = json.loads(content)
        ips = rs["ip"]
        xlog.debug("query_dns_from_xxnet %s cost:%f return:%s", domain, t1 - t0, ips)
        #if dns_type == 1:
        #    ips = [ip for ip in ips if "." in ip]
        ips_out = []
        for ip_cn in ips:
            ip, cn = ip_cn.split("|")
            ips_out.append(ip)
        return ips_out
    except Exception as e:
        xlog.warn("query_dns_from_xxnet %s json:%s parse fail:%s", domain, content, e)
        return []


class LocalDnsQuery():
    def __init__(self, timeout=3):
        self.timeout = timeout
        self.waiters = lru_cache.LruCache(100)
        self.dns_server = self.get_local_dns_server()

        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.sock6 = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
        self.sock.settimeout(1)
        self.sock6.settimeout(1)

        self.running = True
        self.th = threading.Thread(target=self.dns_recv_worker, args=(self.sock,), name="dns_ipv4_receiver")
        self.th.start()

View on GitHub (pinned to cfa5bc17b6)

Solutions

  1. Look at the 'json:' field in the log line to see the actual body — that immediately reveals whether it's an HTML interstitial, an API error message, or a format change.
  2. Verify you're on a current XX-Net version whose parser matches the current dns.xx-net.org response format.
  3. If a captive portal/proxy is intercepting, fix connectivity so the tunnel delivers the real payload.
  4. Report a format-change upstream and patch the parser to tolerate missing '|' (e.g. ip_cn.split('|')[0]).

Example fix

// before
for ip_cn in ips:
    ip, cn = ip_cn.split("|")
    ips_out.append(ip)

// after
for ip_cn in ips:
    ip = ip_cn.split("|")[0]
    if ip:
        ips_out.append(ip)
Defensive patterns

Strategy: try-catch

Validate before calling

# sanity-check contract before relying on the result
ips = query_dns_from_xxnet(domain)
assert isinstance(ips, list) and all(b'.' in ip or ':' in ip for ip in ips), 'bad DNS payload'

Try / catch

try:
    ips = query_dns_from_xxnet(domain)
except Exception:
    ips = []
if not ips:
    ips = socket.gethostbyname_ex(domain)[2]  # fallback to system resolution

Prevention

When it happens

Trigger: Calling query_dns_from_xxnet() when the remote DNS service returns an unexpected body — non-JSON text (error page, HTML), JSON without the expected list structure, or entries not containing the '|' separator, causing ValueError/KeyError/TypeError inside the parse block.

Common situations: The remote dns.xx-net.org API changed format (e.g. dropped the ip|cn pairing); a proxy/captive portal injecting an HTML page; truncated response body; encoding issues where utils.to_str produced garbled text.

Related errors


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