thanos-io/thanos · error

lookup SRV records

Error message

lookup SRV records %q

What it means

For qtype dnssrv/dnssrvnoa, Resolve calls LookupSRV for the host. Failures other than NotFound are wrapped as "lookup SRV records <host>" and returned, meaning the SRV query itself failed (as opposed to the record simply not existing).

Solutions

  1. Verify the SRV record exists and the server responds: dig SRV _service._proto.example.com
  2. Check DNS server connectivity and timeouts; inspect errors.Cause of the wrapped error
  3. Use qtype dns if the target is a plain A record rather than an SRV-based service
  4. If NotFound was intended to be tolerated, confirm the name; NotFound is already tolerated and only logged
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-check SRV availability
_, recs, err := net.LookupSRV("", "", srvName)
if err != nil && !isNXDOMAIN(err) { /* SRV query will likely fail in the library too */ }

Try / catch

res, err := resolver.Resolve(ctx, srvName, dns.SRV)
if err != nil {
    if strings.Contains(err.Error(), "lookup SRV records") {
        cause := errors.Cause(err)
        // log cause; retry on timeout, alert on persistent failure
    }
    return err
}

Prevention

When it happens

Trigger: Resolve(ctx, "_grpc._tcp.example.com", "dnssrv") where the SRV query errors: DNS server unreachable, timeout, SERVFAIL, malformed response, or non-NotFound errors from the underlying resolver (including the SRV recursion-cap error from CNAME loops in SRV answers).

Common situations: Misconfigured SRV discovery names (querying a zone without SRV support via a server that errors rather than NXDOMAINs); DNS outage/firewall blocking UDP/TCP 53; rooted-name issues where the query target is wrong.

Related errors


AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07). Data as JSON: /api/errors/40bcc9d72554e949. Report an issue: GitHub.

Appendix: source

Thrown at pkg/discovery/dns/resolver.go:102

		if err != nil {
			// We exclude error from std Golang resolver for the case of the domain (e.g `NXDOMAIN`) not being found by DNS
			// server. Since `miekg` does not consider this as an error,  when the host cannot be found, empty slice will be
			// returned.
			if !s.resolver.IsNotFound(err) {
				return nil, errors.Wrapf(err, "lookup IP addresses %q", host)
			}
			if ips == nil {
				level.Error(s.logger).Log("msg", "failed to lookup IP addresses", "host", host, "err", err)
			}
		}
		for _, ip := range ips {
			res = append(res, appendScheme(scheme, net.JoinHostPort(ip.String(), port)))
		}
	case SRV, SRVNoA:
		_, recs, err := s.resolver.LookupSRV(ctx, "", "", host)
		if err != nil {
			if !s.resolver.IsNotFound(err) {
				return nil, errors.Wrapf(err, "lookup SRV records %q", host)
			}
			if len(recs) == 0 {
				level.Error(s.logger).Log("msg", "failed to lookup SRV records", "host", host, "err", err)
			}
		}

		for _, rec := range recs {
			// Only use port from SRV record if no explicit port was specified.
			resPort := port
			if resPort == "" {
				resPort = strconv.Itoa(int(rec.Port))
			}

			if qtype == SRVNoA {
				// Remove the final dot from rooted DNS names (this is for compatibility with Prometheus)
				target := strings.TrimRight(rec.Target, ".")
				res = append(res, appendScheme(scheme, net.JoinHostPort(target, resPort)))
				continue

View on GitHub (pinned to 35b8b99117)