apache/druid · error · org.apache.druid.java.util.common.parsers.ParseException

Unknown type[%s] for field[%s]

Error message

Unknown type[%s] for field[%s]

What it means

objectToNumber handles null, Number, and String inputs; anything else (e.g. a Map, List, byte[], or complex object) is not convertible to a number, so with throwParseExceptions=true it throws a ParseException reporting the value's Java class and field name. This catches structural mismatches where a field holds a non-scalar value where a number was expected.

Source

Thrown at processing/src/main/java/org/apache/druid/data/input/Rows.java:166

        asNumber = v;
      }
      catch (Exception e) {
        if (throwParseExceptions) {
          throw new ParseException(
              String.valueOf(inputValue),
              e,
              "Unable to parse value[%s] for field[%s]",
              inputValue,
              name
          );
        } else {
          return null;
        }
      }
    } else {
      if (throwParseExceptions) {
        throw new ParseException(
            String.valueOf(inputValue),
            "Unknown type[%s] for field[%s]",
            inputValue.getClass(),
            name
        );
      } else {
        return null;
      }
    }

    if (outputType == null || asNumber == null) {
      return asNumber;
    } else if (outputType == ValueType.LONG) {
      return asNumber.longValue();
    } else if (outputType == ValueType.FLOAT) {
      return asNumber.floatValue();
    } else if (outputType == ValueType.DOUBLE) {
      return asNumber.doubleValue();

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Add a flattenSpec/transform so the field is extracted to a scalar string or number before numeric conversion.
  2. Convert the value upstream (e.g. parse timestamps to millis longs) before passing to objectToNumber.
  3. Set throwParseExceptions=false to skip unconvertible values (returns null).
  4. Correct the column's type spec so non-numeric fields are not treated as metrics.

Example fix

// before
Number n = Rows.objectToNumber("tags", Collections.singletonList("a"), true);
// after
Number n = Rows.objectToNumber("tags_count", ((List<?>) value).size(), true);
Defensive patterns

Strategy: type-guard

Validate before calling

boolean isScalarNumericCandidate(Object v) {
  return v == null || v instanceof Number || v instanceof String;
}

Type guard

Number toNumberSafe(Object v) {
  if (v instanceof Number) return (Number) v;
  if (v instanceof String) return Rows.objectToNumber("f", v, false);
  return null; // maps, lists, byte[] are not numeric
}

Try / catch

try {
  return Rows.objectToNumber(field, value, true);
} catch (ParseException e) {
  if (e.getMessage() != null && e.getMessage().contains("Unknown type")) {
    log.warn("Field %s holds a non-scalar value of class %s", field, value.getClass());
    return null;
  }
  throw e;
}

Prevention

When it happens

Trigger: Passing a non-scalar input (nested JSON object/array, byte[], Timestamp object) as inputValue to Rows.objectToNumber with throwParseExceptions=true; ingestion mappings where a nested/complex field is wired into a numeric metric.

Common situations: JSON ingestion where the metric column is actually a nested object; flattenSpec producing arrays where scalars were expected; timestamp objects routed into numeric aggregators instead of being converted first.

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/1c2840455f3230c1. Report an issue: GitHub.