{"record":{"id":"a9e1d066cb364716","repo":"hibiken/asynq","slug":"failed-to-get-queue-info-w","errorCode":null,"errorMessage":"failed to get queue info: %w","messagePattern":"failed to get queue info: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"x/metrics/metrics.go","lineNumber":34,"sourceCode":"// It implements prometheus.Collector interface.\n//\n// All metrics exported from this collector have prefix \"asynq\".\ntype QueueMetricsCollector struct {\n\tinspector *asynq.Inspector\n}\n\n// collectQueueInfo gathers QueueInfo of all queues.\n// Since this operation is expensive, it must be called once per collection.\nfunc (qmc *QueueMetricsCollector) collectQueueInfo() ([]*asynq.QueueInfo, error) {\n\tqnames, err := qmc.inspector.Queues()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get queue names: %w\", err)\n\t}\n\tinfos := make([]*asynq.QueueInfo, len(qnames))\n\tfor i, qname := range qnames {\n\t\tqinfo, err := qmc.inspector.GetQueueInfo(qname)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to get queue info: %w\", err)\n\t\t}\n\t\tinfos[i] = qinfo\n\t}\n\treturn infos, nil\n}\n\n// Descriptors used by QueueMetricsCollector\nvar (\n\ttasksQueuedDesc = prometheus.NewDesc(\n\t\tprometheus.BuildFQName(namespace, \"\", \"tasks_enqueued_total\"),\n\t\t\"Number of tasks enqueued; broken down by queue and state.\",\n\t\t[]string{\"queue\", \"state\"}, nil,\n\t)\n\n\tqueueSizeDesc = prometheus.NewDesc(\n\t\tprometheus.BuildFQName(namespace, \"\", \"queue_size\"),\n\t\t\"Number of tasks in a queue\",\n\t\t[]string{\"queue\"}, nil,","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/hibiken/asynq/blob/d135f1439bee74e989b7f9b41ecd542cc87f024a/x/metrics/metrics.go#L16-L52","documentation":"After listing queue names, collectQueueInfo calls Inspector.GetQueueInfo(qname) per queue; any failure fetching a single queue's stats is wrapped with this message and aborts the collection. This is typically a Redis-level error or the queue disappearing between listing and fetching.","triggerScenarios":"Collect → collectQueueInfo; GetQueueInfo fails for one queue due to Redis error, key deleted mid-scrape, cluster resharding, or transient network failure.","commonSituations":"A queue is purged/deleted while Prometheus scrapes; Redis cluster failover; intermittent network issues between the metrics server and Redis.","solutions":["Retry the scrape or add retry logic around GetQueueInfo for transient Redis errors.","Log/unwrap the wrapped cause to see whether it is NOGROUP/missing key vs connection error.","Skip failing queues gracefully instead of failing the entire Collect call.","Verify the queue still exists and that the Inspector connects to the same Redis as the server."],"exampleFix":"// before\nqinfo, err := qmc.inspector.GetQueueInfo(qname)\nif err != nil { return nil, fmt.Errorf(\"failed to get queue info: %w\", err) }\n// after\nqinfo, err := qmc.inspector.GetQueueInfo(qname)\nif err != nil {\n    log.Printf(\"skipping queue %s: %v\", qname, err)\n    continue\n}","handlingStrategy":"fallback","validationCode":"for _, q := range qnames {\n    if _, err := insp.GetQueueInfo(q); err != nil {\n        log.Printf(\"queue %s unavailable: %v\", q, err)\n    }\n}","typeGuard":null,"tryCatchPattern":"qinfo, err := insp.GetQueueInfo(qname)\nif err != nil {\n    log.Printf(\"skipping queue %s: %v\", qname, err)\n    continue // degrade metrics instead of failing scrape\n}","preventionTips":["Avoid deleting queues while metrics scrapes are active, or tolerate missing queues.","Handle Redis NOGROUP/resharding errors in cluster setups.","Add per-queue error counters so partial failures are visible."],"tags":["go","asynq","redis","metrics","prometheus"],"backgroundTag":"database-query-failed","analyzedSha":"d135f1439bee74e989b7f9b41ecd542cc87f024a","analyzedAt":"2026-09-07T19:02:34.660Z","contentChangedAt":"2026-09-07T19:02:34.660Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}