shadowsocks/shadowsocks-rust · error · io::Error

resolve empty

Error message

resolve empty

What it means

In the local DNS server's remote (ACL-routed) lookup path, lookup_remote retries lookup_remote_inner up to `attempts` times; if all attempts fail, the initial "resolve empty" placeholder io::Error is returned to acl_lookup. It indicates the remote DNS upstream never produced a usable response.

Source

Thrown at crates/shadowsocks-service/src/local/dns/server.rs:852

                }
                decision = &mut decider, if !use_remote => {
                    if let Some(local_response) = decision {
                        trace!("pick local response (response): {:?}", local_response);
                        return (local_response, false);
                    } else if let Some(remote_response) = remote_response {
                        trace!("pick remote response (response): {:?}", remote_response);
                        return (remote_response, true);
                    } else {
                        use_remote = true;
                    }
                }
                else => unreachable!(),
            }
        }
    }

    async fn lookup_remote(&self, query: &Query, remote_addr: &Address) -> io::Result<Message> {
        let mut last_err = io::Error::new(ErrorKind::InvalidData, "resolve empty");

        for _ in 0..self.attempts {
            match self.lookup_remote_inner(query, remote_addr).await {
                Ok(m) => {
                    return Ok(m);
                }
                Err(err) => last_err = err,
            }
        }

        Err(last_err)
    }

    async fn lookup_remote_inner(&self, query: &Query, remote_addr: &Address) -> io::Result<Message> {
        let mut message = Message::query();
        message.metadata.recursion_desired = true;
        message.add_query(query.clone());

View on GitHub (pinned to 8eb0f0a65b)

Solutions

  1. Check that the proxy/remote path to the upstream DNS is working (test general connectivity through the proxy)
  2. Verify remote DNS server configuration and reachability
  3. Increase attempts/timeout settings
  4. Review logs for the inner per-attempt error to find the root cause
Defensive patterns

Strategy: retry

Validate before calling

// preflight remote path: query upstream through the proxy before serving DNS
// shadowsocks clients should confirm proxy connectivity first

Try / catch

match server.acl_lookup(query, local).await {
    Err(e) if e.to_string().contains("resolve empty") => {
        // remote upstream unreachable via proxy; retry or answer SERVFAIL
    }
    r => r,
}

Prevention

When it happens

Trigger: acl_lookup routes a query to the remote path and every attempt of lookup_remote_inner (querying remote nameservers, possibly through the proxy) returns Err.

Common situations: Remote/upstream DNS unreachable through the proxy; proxy connection broken; upstream times out; remote nameserver address wrong in config.

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


AI-assisted analysis of shadowsocks/shadowsocks-rust@8eb0f0a65b (2026-09-09). Data as JSON: /api/errors/0e6ada99bbb90587. Report an issue: GitHub.