apache/druid · error · IAE

Unknown type[%s] for metric[%s]

Error message

Unknown type[%s] for metric[%s]

What it means

LegacyTopNMetricSpec.getDimension converts the legacy topN 'metric' field into a dimension name string. It accepts either a plain String or a Map containing a 'metric' key; any other JSON shape (number, array, boolean, null-mapped object without the key handled elsewhere) hits the fallback IllegalArgumentException 'Unknown type[%s] for metric[%s]'. It exists because the legacy metric spec format is lenient but must ultimately resolve to a string.

Source

Thrown at processing/src/main/java/org/apache/druid/query/topn/LegacyTopNMetricSpec.java:40

import com.fasterxml.jackson.annotation.JsonCreator;
import org.apache.druid.java.util.common.IAE;

import java.util.Map;

/**
 */
public class LegacyTopNMetricSpec extends NumericTopNMetricSpec
{
  private static String convertValue(Object metric)
  {
    final String retVal;

    if (metric instanceof String) {
      retVal = (String) metric;
    } else if (metric instanceof Map) {
      retVal = (String) ((Map) metric).get("metric");
    } else {
      throw new IAE("Unknown type[%s] for metric[%s]", metric.getClass(), metric);
    }

    return retVal;
  }

  @JsonCreator
  public LegacyTopNMetricSpec(Object metric)
  {
    super(convertValue(metric));
  }
}

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Change the query's topN 'metric' field to a plain string dimension name
  2. If using an object form, ensure it is {"type":"numeric","metric":"<name>"} or {"type":"lexicographic","metric":"<name>"} with a string 'metric' value
  3. Validate query JSON against the TopNQuery schema before submitting
  4. If building queries in code, pass String instead of raw numbers/objects for the metric

Example fix

// before
{"queryType":"topN","metric": 42, ...}
// after
{"queryType":"topN","metric":"visits", ...}
Defensive patterns

Strategy: validation

Validate before calling

Object metric = queryJson.get("metric");
if (metric instanceof String) { /* ok */ }
else if (metric instanceof Map) {
  Object m = ((Map<?, ?>) metric).get("metric");
  if (!(m instanceof String)) throw new IllegalArgumentException("metric must resolve to a string");
} else {
  throw new IllegalArgumentException("topN metric must be a string or a map with a string 'metric' key");
}

Type guard

boolean isValidTopNMetric(Object metric) {
  return metric instanceof String
      || (metric instanceof Map && ((Map<?, ?>) metric).get("metric") instanceof String);
}

Prevention

When it happens

Trigger: Calling convertValue (via LegacyDimensionSpec) with a topN metric field deserialized as a non-String, non-Map type, e.g. a numeric metric like "metric": 42, a list, or a JSON object missing the 'metric' key producing an unexpected shape in upstream deserialization.

Common situations: Hand-written native topN JSON queries where the metric was written as a number or nested array; clients generating query JSON programmatically with wrong types; queries migrated from older Druid versions where alternate metric encodings were tolerated.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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