{"record":{"id":"47afce6cdbfd08c0","repo":"thanos-io/thanos","slug":"cannot-populate-block-from-no-readers","errorCode":null,"errorMessage":"cannot populate block from no readers","messagePattern":"cannot populate block from no readers","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/compactv2/compactor.go","lineNumber":157,"sourceCode":"\t\t\t}\n\t\t\tp.SeriesProcessed()\n\t\t}\n\t\tif err := set.Err(); err != nil {\n\t\t\tlevel.Error(w.logger).Log(\"msg\", \"error while iterating over set\", \"err\", err)\n\t\t}\n\t\treturn nil\n\t}\n\n\tif err := w.write(ctx, symbols, set, sWriter, p); err != nil {\n\t\treturn errors.Wrap(err, \"write\")\n\t}\n\treturn nil\n}\n\n// compactSeries compacts blocks' series into symbols and one ChunkSeriesSet with lazy populating chunks.\nfunc compactSeries(ctx context.Context, sReaders ...seriesReader) (symbols index.StringIter, set storage.ChunkSeriesSet, _ error) {\n\tif len(sReaders) == 0 {\n\t\treturn nil, nil, errors.New(\"cannot populate block from no readers\")\n\t}\n\n\tvar sets []storage.ChunkSeriesSet\n\tfor i, r := range sReaders {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil, nil, ctx.Err()\n\t\tdefault:\n\t\t}\n\n\t\tk, v := index.AllPostingsKey()\n\t\tall, err := r.ir.Postings(ctx, k, v)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t\tall = r.ir.SortedPostings(all)\n\t\tsyms := r.ir.Symbols()\n\t\tsets = append(sets, newLazyPopulateChunkSeriesSet(r, all))","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/thanos-io/thanos/blob/35b8b991177def87ed52dcf10f9b6d87f07282c8/pkg/compactv2/compactor.go#L139-L175","documentation":"compactSeries refuses to operate on zero series readers and returns a sentinel error \"cannot populate block from no readers\". Like WriteSeries' empty-readers check, this is an internal fail-fast guard: merging zero sources would produce an empty block.","triggerScenarios":"Calling compactSeries directly with no readers; unreachable via WriteSeries in practice because WriteSeries pre-validates len(readers) > 0.","commonSituations":"Tests or custom tooling that call compactSeries directly with a dynamically built reader list that ended up empty; refactoring that bypasses the WriteSeries guard.","solutions":["Check len(sReaders) before calling compactSeries and handle the empty case at the call site","If called from custom code, route through WriteSeries which validates inputs first","Fix upstream logic that builds the reader list so it never produces zero readers for a real compaction"],"exampleFix":"// before\nsymbols, set, err := compactSeries(ctx, sReaders...)\n// after\nif len(sReaders) == 0 {\n    return nil\n}\nsymbols, set, err := compactSeries(ctx, sReaders...)","handlingStrategy":"validation","validationCode":"if len(sReaders) == 0 {\n    return nil, nil, nil // or skip compaction entirely\n}\nsymbols, set, err := compactSeries(ctx, sReaders...)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Route compaction through WriteSeries, which guards empty input","Add assertions/tests for reader-list construction","Treat empty input as a no-op rather than an error in orchestration code"],"tags":["go","compaction","validation"],"backgroundTag":"missing-required-argument","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"}