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

  1. Ensure at least one block.Reader is passed; check len(readers) before calling WriteSeries and skip/return early if empty
  2. Fix the block-selection/compaction-plan logic so a plan with zero sources is never executed
  3. 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

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


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)