ginuerzh/gost · error

resolver: domain %s does not exists

Error message

resolver: domain %s does not exists

What it means

chain.DialWithOptions fails when the configured resolver (and hosts table) cannot resolve the target hostname: c.resolve returns an empty string and the dialer aborts with 'resolver: domain %s does not exists'. It means DNS resolution of the dial address failed at the resolver level, before any network connection was attempted.

Source

Thrown at chain.go:158

}

func (c *Chain) dialWithOptions(ctx context.Context, network, address string, options *ChainOptions) (net.Conn, error) {
	if options == nil {
		options = &ChainOptions{}
	}
	if c == nil {
		c = &Chain{}
	}
	route, err := c.selectRouteFor(address)
	if err != nil {
		return nil, err
	}

	ipAddr := address
	if address != "" {
		ipAddr = c.resolve(address, options.Resolver, options.Hosts)
		if ipAddr == "" {
			return nil, fmt.Errorf("resolver: domain %s does not exists", address)
		}
	}

	timeout := options.Timeout
	if timeout <= 0 {
		timeout = DialTimeout
	}

	var controlFunction func(_ string, _ string, c syscall.RawConn) error = nil
	if c.Mark > 0 {
		controlFunction = func(_, _ string, cc syscall.RawConn) error {
			return cc.Control(func(fd uintptr) {
				ex := setSocketMark(int(fd), c.Mark)
				if ex != nil {
					log.Logf("net dialer set mark %d error: %s", c.Mark, ex)
				} else {
					// log.Logf("net dialer set mark %d success", options.Mark)
				}

View on GitHub (pinned to a33fdbf4c9)

Solutions

  1. Verify the hostname is correct and resolvable: run `dig <domain>` or `nslookup <domain>` against the configured resolver.
  2. Fix the resolver configuration (correct DNS server address/port, or remove the custom resolver to use system DNS).
  3. Add the hostname to the Hosts table (-hosts file or Resolver hosts) as a workaround for NXDOMAIN or internal domains.
  4. If resolution is intermittently failing, retry or add a secondary resolver for redundancy.

Example fix

// before
dialer.DialWithOptions(ctx, "api.mycompany.internal:443", ...) // fails: resolver can't resolve
// after
resolver := net.Resolver{PreferGo: true, Dial: ...} // point at internal DNS
// or map it explicitly in hosts: 10.0.0.5 api.mycompany.internal
Defensive patterns

Strategy: validation

Validate before calling

ips, err := net.LookupHost("api.example.com")
if err != nil || len(ips) == 0 {
    return fmt.Errorf("hostname not resolvable via configured resolver: %v", err)
}

Try / catch

conn, err := d.DialContext(ctx, network, addr)
if err != nil {
    if strings.Contains(err.Error(), "does not exists") {
        // retry with fallback resolver or check hosts table
    }
    return err
}

Prevention

When it happens

Trigger: Dialing a hostname whose domain does not exist (NXDOMAIN), a resolver that cannot answer (wrong DNS server, blocked UDP 53), or Hosts/Resolver options filtering out the name so resolve() returns empty.

Common situations: Typo in the target hostname in the gost config; custom -resolver/-hosts settings pointing to an unreachable or incorrect DNS server; internal-only domains queried against public DNS; transient DNS outages.

Related errors


AI-assisted analysis of ginuerzh/gost@a33fdbf4c9 (2026-09-02). Data as JSON: /api/errors/c7a42bbab2d5ea36. Report an issue: GitHub.