apache/druid · error · IllegalStateException

Unknown version[ ] of MetricHolder

Error message

Unknown version[%s] of MetricHolder

What it means

MetricHolder.fromByteBuffer reads a legacy (v8) segment metric column and throws ISE if the version byte is not the expected VERSION[0]. This protects against reading metric columns in an on-disk format the loader cannot parse.

Solutions

  1. Verify segment integrity (re-download/re-pull the segment from deep storage)
  2. Re-ingest the affected segments so they are written in the current format
  3. Upgrade Druid if the segments were written by a newer format than the reader supports

Example fix

null
Defensive patterns

Strategy: try-catch

Validate before calling

// check segment descriptor/version metadata before loading legacy metric columns
if (!segmentVersion.equals("v8-compatible")) { re-ingest; }

Try / catch

try { MetricHolder.fromByteBuffer(buf); } catch (ISE e) { if (e.getMessage().contains("Unknown version")) { /* quarantine/re-download segment */ } else throw e; }

Prevention

When it happens

Trigger: Reading a metric column whose stored version byte differs from the expected one — corrupted segment files, hand-modified segments, or segments written by incompatible Druid versions.

Common situations: Mounting segments copied from a different Druid version or disk-format era; truncated/corrupted segment files on deep storage or local cache.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/92f3a62a57aadc44. Report an issue: GitHub.

Appendix: source

Thrown at processing/src/main/java/org/apache/druid/segment/MetricHolder.java:48

import java.nio.ByteBuffer;
import java.nio.ByteOrder;

/**
 */
public class MetricHolder
{
  private static final byte[] VERSION = new byte[]{0x0};
  private static final SerializerUtils SERIALIZER_UTILS = new SerializerUtils();

  /**
   * Read a metric column from a legacy (v8) segment.
   */
  public static MetricHolder fromByteBuffer(ByteBuffer buf)
  {
    final byte ver = buf.get();
    if (VERSION[0] != ver) {
      throw new ISE("Unknown version[%s] of MetricHolder", ver);
    }

    final String metricName = SERIALIZER_UTILS.readString(buf);
    final String typeName = SERIALIZER_UTILS.readString(buf);
    MetricHolder holder = new MetricHolder(metricName, typeName);

    switch (holder.type) {
      case FLOAT:
        holder.floatType = CompressedColumnarFloatsSupplier.fromByteBuffer(
            buf,
            ByteOrder.nativeOrder(),
            null // OK since this method is only used for legacy segments, which always use version 1 indexed
        );
        break;
      case COMPLEX:
        final ComplexMetricSerde serdeForType = ComplexMetrics.getSerdeForType(holder.getTypeName());

        if (serdeForType == null) {

View on GitHub (pinned to 9b90983fd2)