{"record":{"id":"0492b611d2a65ab0","repo":"thanos-io/thanos","slug":"open-index-file","errorCode":null,"errorMessage":"open index file","messagePattern":"open index file","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"pkg/block/index.go","lineNumber":221,"sourceCode":"\t\tn.max = v\n\t}\n}\n\nfunc (n *minMaxSumInt64) Avg() int64 {\n\tif n.cnt == 0 {\n\t\treturn 0\n\t}\n\treturn n.sum / n.cnt\n}\n\n// GatherIndexHealthStats returns useful counters as well as outsider chunks (chunks outside of block time range) that\n// helps to assess index health.\n// It considers https://github.com/prometheus/tsdb/issues/347 as something that Thanos can handle.\n// See HealthStats.Issue347OutsideChunks for details.\nfunc GatherIndexHealthStats(ctx context.Context, logger log.Logger, fn string, minTime, maxTime int64) (stats HealthStats, err error) {\n\tr, err := index.NewFileReader(fn, index.DecodePostingsRaw)\n\tif err != nil {\n\t\treturn stats, errors.Wrap(err, \"open index file\")\n\t}\n\tdefer runutil.CloseWithErrCapture(&err, r, \"gather index issue file reader\")\n\n\tkey, value := index.AllPostingsKey()\n\tp, err := r.Postings(ctx, key, value)\n\tif err != nil {\n\t\treturn stats, errors.Wrap(err, \"get all postings\")\n\t}\n\tvar (\n\t\tlset     labels.Labels\n\t\tprevLset labels.Labels\n\t\tbuilder  labels.ScratchBuilder\n\n\t\tchks []chunks.Meta\n\n\t\tseriesLifeDuration                          = newMinMaxSumInt64()\n\t\tseriesLifeDurationWithoutSingleSampleSeries = newMinMaxSumInt64()\n\t\tseriesChunks                                = newMinMaxSumInt64()","sourceCodeStart":203,"sourceCodeEnd":239,"githubUrl":"https://github.com/thanos-io/thanos/blob/35b8b991177def87ed52dcf10f9b6d87f07282c8/pkg/block/index.go#L203-L239","documentation":"GatherIndexHealthStats wraps failures from index.NewFileReader with the message 'open index file'. This means the block's index file could not be opened/parsed as a TSDB index (missing file, truncated download, corrupt magic/TOC, wrong format version), so the index health walk cannot even begin.","triggerScenarios":"Calling GatherIndexHealthStats, VerifyIndex, or processDownsampling (which all call it) with an fn path where the index file is absent, unreadable, partially uploaded to object storage, or not a valid TSDB index file; index.NewFileReader fails and the error is wrapped with 'open index file'.","commonSituations":"Block directory missing the 'index' file because upload was interrupted; corrupt or partially synced object storage download; permissions preventing read; the file path passed points to the wrong directory; disk/network errors during local block sync.","solutions":["Check the file exists and is readable at fn (ls/stat the path) and that you are pointing at the block directory's 'index' file.","Re-download or re-upload the block to object storage; check sync/upload logs for truncation.","Restore the block from a backup or re-upload from source Prometheus data; delete the corrupted block so compactor can replace it.","Check disk space, permissions, and mount health on the local cache directory if blocks are synced locally."],"exampleFix":"// before: path may not contain index\nstats, err := block.GatherIndexHealthStats(ctx, logger, filepath.Join(dir, id.String()), minTime, maxTime)\n// after: validate path first\nindexFn := filepath.Join(dir, id.String(), block.IndexFilename)\nif _, err := os.Stat(indexFn); err != nil {\n    return errors.Wrapf(err, \"index file missing for block %s\", id)\n}\nstats, err := block.GatherIndexHealthStats(ctx, logger, indexFn, minTime, maxTime)","handlingStrategy":"validation","validationCode":"indexFn := filepath.Join(dir, id.String(), \"index\")\nfi, err := os.Stat(indexFn)\nif err != nil { return errors.Wrapf(err, \"index file missing: %s\", indexFn) }\nif fi.Size() == 0 { return errors.Errorf(\"index file is empty: %s\", indexFn) }","typeGuard":"func indexFileReadable(path string) bool {\n    fi, err := os.Stat(path)\n    return err == nil && !fi.IsDir() && fi.Size() > 0\n}","tryCatchPattern":"stats, err := block.GatherIndexHealthStats(ctx, logger, indexFn, minTime, maxTime)\nif err != nil {\n    if strings.Contains(err.Error(), \"open index file\") {\n        return reDownloadBlock(ctx, dir, id)\n    }\n    return err\n}","preventionTips":["Verify block uploads complete before removing local copies","Check file presence/size before health analysis","Watch disk/network errors during block sync from object storage"],"tags":["file-not-found","tsdb","block-index","thanos","io"],"backgroundTag":"file-not-found","analyzedSha":"35b8b991177def87ed52dcf10f9b6d87f07282c8","analyzedAt":"2026-09-07T01:49:59.689Z","contentChangedAt":"2026-09-07T01:49:59.689Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}