cloudflare/cloudflared · error

no TXT record found for %s to determine which features to op

Error message

no TXT record found for %s to determine which features to opt-in

What it means

The feature selector determines opt-in features by reading a DNS TXT record on a per-account feature selector hostname. lookupRecord queries the TXT records via a resolver; when the lookup succeeds but returns zero records, this error is thrown because there is no TXT payload from which to determine feature opt-ins. It is distinct from a DNS lookup failure — DNS answered, but the expected TXT record simply does not exist for that hostname.

Source

Thrown at features/selector.go:197

}

func newDNSResolver() *dnsResolver {
	return &dnsResolver{
		resolver: net.DefaultResolver,
	}
}

func (dr *dnsResolver) lookupRecord(ctx context.Context) ([]byte, error) {
	ctx, cancel := context.WithTimeout(ctx, lookupTimeout)
	defer cancel()

	records, err := dr.resolver.LookupTXT(ctx, featureSelectorHostname)
	if err != nil {
		return nil, err
	}

	if len(records) == 0 {
		return nil, fmt.Errorf("no TXT record found for %s to determine which features to opt-in", featureSelectorHostname)
	}

	return []byte(records[0]), nil
}

func switchThreshold(accountTag string) uint32 {
	h := fnv.New32a()
	_, _ = h.Write([]byte(accountTag))
	return h.Sum32() % 100
}

View on GitHub (pinned to 2253eeeb25)

Solutions

  1. Retry — the selector is re-queried periodically and a missing record often appears after propagation.
  2. Verify the hostname and its records manually: 'nslookup -type=TXT <featureSelectorHostname>' using a public resolver (e.g. 1.1.1.1) to rule out a local resolver issue.
  3. Confirm the account tag (from the tunnel credentials / dashboard) is correct, since it determines the selector hostname.
  4. If you run a custom resolver or firewall, allow TXT queries to Cloudflare's feature-selector domain; consider falling back to default feature behavior when this error occurs, as the code treats it as a hard failure of the opt-in check.

Example fix

// diagnosing — check the TXT record out-of-band:
//   $ dig TXT <account>-feature-lookup.cloudflareclient.com +short
// after — if the local resolver returns empty, query a public one or retry later;
// the selector hostname depends on the account tag, so also re-copy the tag from the dashboard.
Defensive patterns

Strategy: try-catch

Validate before calling

func featureTXTExists(hostname string, resolver *net.Resolver) error {
    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()
    records, err := resolver.LookupTXT(ctx, hostname)
    if err != nil {
        return err
    }
    if len(records) == 0 {
        return fmt.Errorf("pre-check: no TXT record for %s", hostname)
    }
    return nil
}

Try / catch

features, err := selector.LookupFeatures(ctx, accountTag)
if err != nil {
    if strings.Contains(err.Error(), "no TXT record found") {
        logger.Info().Msg("no feature TXT record; using default feature set")
        return defaultFeatures, nil // treat empty TXT as opt-out defaults
    }
    return nil, err // real DNS failure: surface it
}

Prevention

When it happens

Trigger: Calling the feature-selector lookup (dr.resolver.LookupTXT on featureSelectorHostname, built from the account tag) where DNS returns success with an empty record set: the account has no feature TXT record published, the account tag used to build the hostname is wrong, or a caching/recursive resolver returned an empty answer.

Common situations: Newly created Cloudflare Zero Trust accounts before feature records propagate; misconfigured account tag producing a hostname with no TXT record; custom or corporate resolvers that filter or fail to forward TXT queries for the selector domain; DNS propagation delays right after account feature changes.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of cloudflare/cloudflared@2253eeeb25 (2026-09-06). Data as JSON: /api/errors/96c36923749f833a. Report an issue: GitHub.