{"record":{"id":"6d3f05fda4890552","repo":"nsqio/nsq","slug":"failed-to-query-any-nsqlookupd-s","errorCode":null,"errorMessage":"failed to query any nsqlookupd: %s","messagePattern":"failed to query any nsqlookupd: (.+?)","errorType":"http","errorClass":null,"httpStatus":502,"severity":"error","filePath":"internal/clusterinfo/data.go","lineNumber":108,"sourceCode":"\n\t\t\tvar resp respType\n\t\t\terr := c.client.GETV1(endpoint, &resp)\n\t\t\tif err != nil {\n\t\t\t\tlock.Lock()\n\t\t\t\terrs = append(errs, err)\n\t\t\t\tlock.Unlock()\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tlock.Lock()\n\t\t\tdefer lock.Unlock()\n\t\t\ttopics = append(topics, resp.Topics...)\n\t\t}(addr)\n\t}\n\twg.Wait()\n\n\tif len(errs) == len(lookupdHTTPAddrs) {\n\t\treturn nil, fmt.Errorf(\"failed to query any nsqlookupd: %s\", ErrList(errs))\n\t}\n\n\ttopics = stringy.Uniq(topics)\n\tsort.Strings(topics)\n\n\tif len(errs) > 0 {\n\t\treturn topics, ErrList(errs)\n\t}\n\treturn topics, nil\n}\n\n// GetLookupdTopicChannels returns a []string containing a union of all the channels\n// from all the given lookupd for the given topic\nfunc (c *ClusterInfo) GetLookupdTopicChannels(topic string, lookupdHTTPAddrs []string) ([]string, error) {\n\tvar channels []string\n\tvar lock sync.Mutex\n\tvar wg sync.WaitGroup\n\tvar errs []error","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/nsqio/nsq/blob/85cf10c09c6c3c86160d6f0eb156f62d0efc1648/internal/clusterinfo/data.go#L90-L126","documentation":"ClusterInfo.GetLookupdTopics fans out HTTP requests to every nsqlookupd in parallel and merges topic lists. It only fails hard when the error count equals the number of addresses, i.e. every single nsqlookupd failed (dial errors, timeouts, non-2xx, or JSON decode failures); partial failures still return the merged topics plus an ErrList. This is the message nsqadmin shows when its --lookupd-http-address list is entirely unreachable.","triggerScenarios":"Calling GetLookupdTopics with addresses where no nsqlookupd is reachable: wrong host/port in --lookupd-http-address, lookupd processes down, firewall/DNS failure, or HTTPS-vs-HTTP scheme mismatch.","commonSituations":"nsqadmin deployed with a stale lookupd address after a cluster migration; lookupd restarted on a different port; network policy blocking the admin UI's egress; all replicas of nsqlookupd stopped for maintenance while someone opens the admin page.","solutions":["Verify each address responds: curl http://<lookupd>:4161/topics","Correct --lookupd-http-address entries (must be http addresses, e.g. 10.0.0.1:4161)","Start or restart the nsqlookupd instances, then retry","Check DNS resolution and firewall rules from the nsqadmin host"],"exampleFix":"# before\n--lookupd-http-address=10.0.0.1:4160   # wrong port (this is TCP)\n\n# after\n--lookupd-http-address=10.0.0.1:4161","handlingStrategy":"retry","validationCode":"// preflight each lookupd before the call\nfor _, a := range lookupdAddrs {\n\tresp, err := http.Get(\"http://\" + a + \"/topics\")\n\tif err != nil || resp.StatusCode != 200 {\n\t\tlog.Printf(\"lookupd %s unhealthy: %v\", a, err)\n\t}\n\tif resp != nil {\n\t\tresp.Body.Close()\n\t}\n}","typeGuard":null,"tryCatchPattern":"var topics []string\nvar err error\nfor i := 0; i < 3; i++ {\n\ttopics, err = ci.GetLookupdTopics(addrs)\n\tif err == nil {\n\t\tbreak\n\t}\n\ttime.Sleep(time.Duration(i+1) * 500 * time.Millisecond)\n}\nif err != nil {\n\treturn fmt.Errorf(\"all lookupd unreachable: %w\", err)\n}","preventionTips":["Run >=2 nsqlookupd replicas and list all of them in --lookupd-http-address","Monitor lookupd /health from the nsqadmin host","Remember partial failures still return data with an ErrList - distinguish the two cases"],"tags":["clusterinfo","nsqlookupd","network","http","discovery"],"backgroundTag":null,"analyzedSha":"85cf10c09c6c3c86160d6f0eb156f62d0efc1648","analyzedAt":"2026-08-16T00:53:05.009Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}