apache/druid · error · IllegalArgumentException

Encountered metric with null or empty name at position

Error message

Encountered metric with null or empty name at position %d

What it means

During DataSchema construction, output field names for aggregators are computed and validated. Every aggregator must have a non-null, non-empty name because metric names become column identifiers; a blank name cannot be indexed, so this IAE pinpoints the offending position.

Solutions

  1. Add a unique, non-empty "name" to every aggregator in metricsSpec.
  2. Check aggregator factories created programmatically call setName(...) with a real value.
  3. Validate the spec JSON (names non-empty) before submitting the ingestion task.

Example fix

// before
{ "type": "count", "name": null }
// after
{ "type": "count", "name": "rowCount" }
Defensive patterns

Strategy: validation

Validate before calling

for (AggregatorFactory agg : dataSchema.getAggregators()) {
  if (agg == null || agg.getName() == null || agg.getName().isEmpty()) {
    throw new IllegalArgumentException("Every aggregator must have a non-empty name");
  }
}

Prevention

When it happens

Trigger: Building a DataSchema whose metricsSpec contains an aggregator (e.g. count, doubleSum, longSum) with name omitted, null, or "", or with a post-aggregator referencing an unnamed aggregator.

Common situations: Hand-written or templated ingestion specs where the "name" key was deleted, JSON with a typo like "nane", or programmatic spec builders not setting the aggregator name.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at server/src/main/java/org/apache/druid/segment/indexing/DataSchema.java:553

                    field,
                    dimSchema.getColumnType()
                );
          } else if (!sawTimeDimension) {
            // Skip adding __time to "fields" (once) if it's listed as a dimension, so it doesn't show up as an error.
            sawTimeDimension = true;
            continue;
          }
        }

        fields.computeIfAbsent(field, k -> TreeMultiset.create()).add("dimensions list");
      }
    }

    if (aggregators != null) {
      for (int i = 0; i < aggregators.length; i++) {
        final String field = aggregators[i].getName();
        if (Strings.isNullOrEmpty(field)) {
          throw new IAE("Encountered metric with null or empty name at position %d", i);
        }

        fields.computeIfAbsent(field, k -> TreeMultiset.create()).add("metricsSpec list");
      }
    }

    return getFieldsOrThrowIfErrors(fields);
  }

  /**
   * Validates that each {@link AggregateProjectionSpec} does not have duplicate column names in
   * {@link AggregateProjectionSpec#groupingColumns} and {@link AggregateProjectionSpec#aggregators} and that segment
   * {@link Granularity} is at least as coarse as {@link AggregateProjectionSchema#effectiveGranularity}
   */
  public static void validateProjections(
      @Nullable List<AggregateProjectionSpec> projections,
      @Nullable Granularity segmentGranularity
  )

View on GitHub (pinned to 9b90983fd2)