thanos-io/thanos · error
cannot write from no readers
Error message
cannot write from no readers
What it means
Compactor.WriteSeries refuses to run when the readers slice is empty. Compaction works by merging series from one or more block readers into a new block; with zero readers there is nothing to compact, so the call fails fast with a sentinel error instead of producing an empty or corrupt block.
Solutions
- Ensure at least one block.Reader is passed; check len(readers) before calling WriteSeries and skip/return early if empty
- Fix the block-selection/compaction-plan logic so a plan with zero sources is never executed
- If an empty input is legitimate for your flow, guard the call site: if len(readers) == 0 { return nil }
Example fix
// before
if err := comp.WriteSeries(ctx, readers, w, progress); err != nil { ... }
// after
if len(readers) > 0 {
if err := comp.WriteSeries(ctx, readers, w, progress); err != nil { ... }
} Defensive patterns
Strategy: validation
Validate before calling
if len(readers) == 0 {
// nothing to compact; skip instead of calling WriteSeries
return nil
}
if err := comp.WriteSeries(ctx, readers, sWriter, progress); err != nil {
return err
} Try / catch
if err := comp.WriteSeries(ctx, readers, sWriter, progress); err != nil {
if err.Error() == "cannot write from no readers" {
return nil // treat empty input as a no-op
}
return err
} Prevention
- Always validate len(readers) > 0 before invoking WriteSeries
- Make block-selection logic return an explicit 'no plan' state instead of an empty reader list
- Add unit tests covering empty compaction groups
When it happens
Trigger: Calling WriteSeries with a nil or zero-length []block.Reader slice, e.g. after filtering out all source blocks or passing a slice built from an empty compaction group.
Common situations: Compaction planning code selecting source blocks yields no candidates (e.g. all blocks excluded by time range or already compacted) but WriteSeries is still invoked; tests or tooling that construct Compactor calls manually with no inputs.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- cannot populate block from no readers
- failed to parse the template
- failed to execute the template
- found that TSDB Max time is
- unexpected meta file version
AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07).
Data as JSON: /api/errors/7fd6ddab73fbac8a.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/compactv2/compactor.go:79
func New(tmpDir string, logger log.Logger, changeLogger ChangeLogger, pool chunkenc.Pool) *Compactor {
return &Compactor{
tmpDir: tmpDir,
logger: logger,
changeLogger: changeLogger,
chunkPool: pool,
}
}
func NewDryRun(tmpDir string, logger log.Logger, changeLogger ChangeLogger, pool chunkenc.Pool) *Compactor {
s := New(tmpDir, logger, changeLogger, pool)
s.dryRun = true
return s
}
// TODO(bwplotka): Upstream this.
func (w *Compactor) WriteSeries(ctx context.Context, readers []block.Reader, sWriter block.Writer, p ProgressLogger, modifiers ...Modifier) (err error) {
if len(readers) == 0 {
return errors.New("cannot write from no readers")
}
var (
sReaders []seriesReader
closers []io.Closer
)
defer func() {
errs := tsdb_errors.NewMulti(err)
if cerr := tsdb_errors.CloseAll(closers); cerr != nil {
errs.Add(errors.Wrap(cerr, "close"))
}
err = errs.Err()
}()
for _, b := range readers {
indexr, err := b.Index()
if err != nil {
return errors.Wrapf(err, "open index reader for block %+v", b.Meta())View on GitHub (pinned to 35b8b99117)