VictoriaMetrics/VictoriaMetrics · error

invalid MinTimestamp at block header at offset %d; got %d; c

Error message

invalid MinTimestamp at block header at offset %d; got %d; cannot be smaller than %d

What it means

Each part header declares the minimum timestamp (ph.MinTimestamp) across all rows in the part. Every block header must have MinTimestamp >= the part's minimum. A smaller value means the index content contradicts the part metadata — corruption or mismatched files. This guard keeps query-time timestamp filtering correct.

Source

Thrown at lib/storage/block_stream_reader.go:254

		return fmt.Errorf("cannot parse block header read from index data at offset %d: %w", bsr.prevIndexBlockOffset(), err)
	}
	if len(tail) > 0 {
		return fmt.Errorf("non-empty tail left after parsing block header at offset %d: %x", bsr.prevIndexBlockOffset(), tail)
	}
	bsr.indexCursor = bsr.indexCursor[marshaledBlockHeaderSize:]

	bsr.blocksCount++
	if bsr.blocksCount > bsr.ph.BlocksCount {
		return fmt.Errorf("too many blocks found in the block stream; got %d; cannot be bigger than %d", bsr.blocksCount, bsr.ph.BlocksCount)
	}

	// Validate block header.
	bsr.rowsCount += uint64(bsr.Block.bh.RowsCount)
	if bsr.rowsCount > bsr.ph.RowsCount {
		return fmt.Errorf("too many rows found in the block stream; got %d; cannot be bigger than %d", bsr.rowsCount, bsr.ph.RowsCount)
	}
	if bsr.Block.bh.MinTimestamp < bsr.ph.MinTimestamp {
		return fmt.Errorf("invalid MinTimestamp at block header at offset %d; got %d; cannot be smaller than %d",
			bsr.prevIndexBlockOffset(), bsr.Block.bh.MinTimestamp, bsr.ph.MinTimestamp)
	}
	if bsr.Block.bh.MaxTimestamp > bsr.ph.MaxTimestamp {
		return fmt.Errorf("invalid MaxTimestamp at block header at offset %d; got %d; cannot be bigger than %d",
			bsr.prevIndexBlockOffset(), bsr.Block.bh.MaxTimestamp, bsr.ph.MaxTimestamp)
	}
	usePrevTimestamps := len(bsr.prevTimestampsData) > 0 && bsr.Block.bh.TimestampsBlockOffset == bsr.prevTimestampsBlockOffset
	if usePrevTimestamps {
		if int(bsr.Block.bh.TimestampsBlockSize) != len(bsr.prevTimestampsData) {
			return fmt.Errorf("invalid TimestampsBlockSize at block header at offset %d; got %d; want %d",
				bsr.prevIndexBlockOffset(), bsr.Block.bh.TimestampsBlockSize, len(bsr.prevTimestampsData))
		}
	} else if bsr.Block.bh.TimestampsBlockOffset != bsr.timestampsBlockOffset {
		return fmt.Errorf("invalid TimestampsBlockOffset at block header at offset %d; got %d; want %d",
			bsr.prevIndexBlockOffset(), bsr.Block.bh.TimestampsBlockOffset, bsr.timestampsBlockOffset)
	}
	if bsr.Block.bh.ValuesBlockOffset != bsr.valuesBlockOffset {
		return fmt.Errorf("invalid ValuesBlockOffset at block header at offset %d; got %d; want %d",

View on GitHub (pinned to 5079fb58f1)

Solutions

  1. Restore the entire part directory from a backup or healthy replica so header and index agree.
  2. Check for leftover tmp/partial parts from interrupted merges and delete them.
  3. Remove the inconsistent part and re-ingest the affected time range if no backup exists.
  4. If many parts are affected, investigate the storage device for silent corruption.

Example fix

// before: part header and index from different merges
// invalid MinTimestamp at block header at offset 8192; got 100; cannot be smaller than 200
// after: restore a self-consistent part
rsync -a --checksum backup:/vmdata/parts/2026_01/ /vmdata/parts/2026_01/
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the part directory is complete and self-consistent before streaming:
func partSelfConsistent(partPath string) error {
	for _, f := range []string{"metadata.json", "index.bin", "metaindex.bin", "timestamps.bin", "values.bin"} {
		if _, err := os.Stat(filepath.Join(partPath, f)); err != nil {
			return fmt.Errorf("missing %s in %s: %w", f, partPath, err)
		}
	}
	return nil
}

Try / catch

if err := bsr.Error(); err != nil {
	if strings.Contains(err.Error(), "invalid MinTimestamp") {
		// index contradicts part header: restore whole part or re-ingest range
	}
	return err
}

Prevention

When it happens

Trigger: Calling NextBlock when bsr.Block.bh.MinTimestamp < bsr.ph.MinTimestamp — typically an index file paired with the wrong part header, corrupted timestamp fields, or files mixed from different merges/versions.

Common situations: Manual part copies during migrations; interrupted compaction leaving stale metadata; disk corruption; externally rewritten VM files.

Related errors


AI-assisted analysis of VictoriaMetrics/VictoriaMetrics@5079fb58f1 (2026-09-03). Data as JSON: /api/errors/3df42e7ca62ffa65. Report an issue: GitHub.