{"record":{"id":"f85783598d4932aa","repo":"VictoriaMetrics/VictoriaMetrics","slug":"error-when-counting-unique-timeseries-w","errorCode":null,"errorMessage":"error when counting unique timeseries: %w","messagePattern":"error when counting unique timeseries: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lib/storage/index_db.go","lineNumber":1301,"sourceCode":"\tts.Seek(kb.B)\n\tfor ts.NextItem() {\n\t\tif loopsPaceLimiter&paceLimiterFastIterationsMask == 0 {\n\t\t\tif err := checkSearchDeadlineAndPace(is.deadline); err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t}\n\t\tloopsPaceLimiter++\n\t\titem := ts.Item\n\t\tif !bytes.HasPrefix(item, kb.B) {\n\t\t\tbreak\n\t\t}\n\t\t// Take into account deleted timeseries too.\n\t\t// It is OK if series can be counted multiple times in rare cases -\n\t\t// the returned number is an estimation.\n\t\tmetricIDsLen++\n\t}\n\tif err := ts.Error(); err != nil {\n\t\treturn 0, fmt.Errorf(\"error when counting unique timeseries: %w\", err)\n\t}\n\treturn metricIDsLen, nil\n}\n\n// GetTSDBStatus returns topN entries for tsdb status for the given tfss, date and focusLabel.\nfunc (db *indexDB) GetTSDBStatus(qt *querytracer.Tracer, tfss []*TagFilters, date uint64, focusLabel string, topN, maxMetrics int, deadline uint64) (*TSDBStatus, error) {\n\tqt = qt.NewChild(\"collect TSDB status: filters=%s, date=%s, focusLabel=%q, topN=%d, maxMetrics=%d\", tfss, dateToString(date), focusLabel, topN, maxMetrics)\n\tdefer qt.Done()\n\n\tif !db.legacyContainsDate(date) {\n\t\tqt.Printf(\"indexDB doesn't contain data for the given date: %s\", dateToString(date))\n\t\treturn &TSDBStatus{}, nil\n\t}\n\n\tis := db.getIndexSearch(deadline)\n\tdefer db.putIndexSearch(is)\n\tstatus, err := is.getTSDBStatus(qt, tfss, date, focusLabel, topN, maxMetrics)\n\tif err != nil {","sourceCodeStart":1283,"sourceCodeEnd":1319,"githubUrl":"https://github.com/VictoriaMetrics/VictoriaMetrics/blob/5079fb58f1e8e62113f90c945ad71586c797d770/lib/storage/index_db.go#L1283-L1319","documentation":"Wraps an index-iteration failure while counting unique timeseries (TSDB status / cardinality counting). The count is estimated by scanning metricIDs from the index; if the scan errors, the count is abandoned with this annotated error.","triggerScenarios":"Calling GetTSDBCountSeries / TSDB status APIs when the index search over the metricName index errors: I/O failure, corrupted part, or deadline exceeded during heavy scans.","commonSituations":"Heavy cardinality scans timing out; disk issues on -storageDataPath; concurrent merges slowing scans past deadlines.","solutions":["Check the wrapped cause (deadline vs I/O vs corruption)","Increase the search deadline or reduce topN/maxMetrics scope","Verify index integrity and repair/restore corrupted parts if needed","Retry during lower load"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// keep TSDB status scope modest before invoking\nif topN <= 0 || maxMetrics <= 0 {\n    return errors.New(\"invalid status params\")\n}","typeGuard":null,"tryCatchPattern":"n, err := db.GetTSDBCountSeries(qt, tfss, date, deadline)\nif err != nil {\n    if strings.Contains(err.Error(), \"deadline\") {\n        // retry with larger deadline\n    } else {\n        // check storage health\n    }\n    return 0\n}","preventionTips":["Schedule heavy cardinality stats off-peak","Use narrow focusLabel and date ranges","Keep storage disks healthy and monitored","Bound maxMetrics to available memory"],"tags":["storage","index-db","cardinality","corruption"],"backgroundTag":"index-search-failed","analyzedSha":"5079fb58f1e8e62113f90c945ad71586c797d770","analyzedAt":"2026-09-03T18:10:26.153Z","contentChangedAt":"2026-09-03T18:10:26.153Z","schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}