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
- Restore the entire part directory from a backup or healthy replica so header and index agree.
- Check for leftover tmp/partial parts from interrupted merges and delete them.
- Remove the inconsistent part and re-ingest the affected time range if no backup exists.
- 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
- Keep part header, index, and data files from the same merge together at all times.
- Delete tmp/partial parts left behind by interrupted compactions.
- Restore parts only from consistent, checksum-verified backups.
- Check storage health if timestamp inconsistencies appear across many parts.
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
- invalid number of block headers in the previous index block
- too short index data for reading block header at offset %d;
- cannot parse block header read from index data at offset %d:
- non-empty tail left after parsing block header at offset %d:
- too many blocks found in the block stream; got %d; cannot be
AI-assisted analysis of VictoriaMetrics/VictoriaMetrics@5079fb58f1 (2026-09-03).
Data as JSON: /api/errors/3df42e7ca62ffa65.
Report an issue: GitHub.