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
- Retry — the selector is re-queried periodically and a missing record often appears after propagation.
- 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.
- Confirm the account tag (from the tunnel credentials / dashboard) is correct, since it determines the selector hostname.
- 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
- Copy the account tag exactly from the Cloudflare dashboard; it builds the selector hostname
- Allow TXT queries to Cloudflare domains through corporate resolvers/firewalls
- Use a public resolver (1.1.1.1) to cross-check when local DNS returns empty answers
- Design callers to fall back to default features when the opt-in record is absent, since new accounts legitimately have no TXT record yet
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
- SRV record %v had no IPs
- expected at least 2 Cloudflare Regions regions, but SRV only
- failed to resolve any edge address
- unable to resolve host to confirm access
- failed to fetch JWKS from %s
AI-assisted analysis of cloudflare/cloudflared@2253eeeb25 (2026-09-06).
Data as JSON: /api/errors/96c36923749f833a.
Report an issue: GitHub.