{"record":{"id":"96c36923749f833a","repo":"cloudflare/cloudflared","slug":"no-txt-record-found-for-s-to-determine-which-feat","errorCode":null,"errorMessage":"no TXT record found for %s to determine which features to opt-in","messagePattern":"no TXT record found for (.+?) to determine which features to opt-in","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"features/selector.go","lineNumber":197,"sourceCode":"}\n\nfunc newDNSResolver() *dnsResolver {\n\treturn &dnsResolver{\n\t\tresolver: net.DefaultResolver,\n\t}\n}\n\nfunc (dr *dnsResolver) lookupRecord(ctx context.Context) ([]byte, error) {\n\tctx, cancel := context.WithTimeout(ctx, lookupTimeout)\n\tdefer cancel()\n\n\trecords, err := dr.resolver.LookupTXT(ctx, featureSelectorHostname)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif len(records) == 0 {\n\t\treturn nil, fmt.Errorf(\"no TXT record found for %s to determine which features to opt-in\", featureSelectorHostname)\n\t}\n\n\treturn []byte(records[0]), nil\n}\n\nfunc switchThreshold(accountTag string) uint32 {\n\th := fnv.New32a()\n\t_, _ = h.Write([]byte(accountTag))\n\treturn h.Sum32() % 100\n}\n","sourceCodeStart":179,"sourceCodeEnd":208,"githubUrl":"https://github.com/cloudflare/cloudflared/blob/2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f/features/selector.go#L179-L208","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// diagnosing — check the TXT record out-of-band:\n//   $ dig TXT <account>-feature-lookup.cloudflareclient.com +short\n// after — if the local resolver returns empty, query a public one or retry later;\n// the selector hostname depends on the account tag, so also re-copy the tag from the dashboard.","handlingStrategy":"try-catch","validationCode":"func featureTXTExists(hostname string, resolver *net.Resolver) error {\n    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n    defer cancel()\n    records, err := resolver.LookupTXT(ctx, hostname)\n    if err != nil {\n        return err\n    }\n    if len(records) == 0 {\n        return fmt.Errorf(\"pre-check: no TXT record for %s\", hostname)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"features, err := selector.LookupFeatures(ctx, accountTag)\nif err != nil {\n    if strings.Contains(err.Error(), \"no TXT record found\") {\n        logger.Info().Msg(\"no feature TXT record; using default feature set\")\n        return defaultFeatures, nil // treat empty TXT as opt-out defaults\n    }\n    return nil, err // real DNS failure: surface it\n}","preventionTips":["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"],"tags":["network","dns","txt-record","feature-flags","empty-response"],"backgroundTag":"record-not-found","analyzedSha":"2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f","analyzedAt":"2026-09-06T04:14:33.757Z","contentChangedAt":"2026-09-06T04:14:33.757Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}