{"record":{"id":"cf8f5b6a2f4afd92","repo":"apache/druid","slug":"unable-to-handle-type-s-for-aggregatorfactory-s","errorCode":null,"errorMessage":"Unable to handle type[%s] for AggregatorFactory[%s]","messagePattern":"Unable to handle type\\[(.+?)\\] for AggregatorFactory\\[(.+?)\\]","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/segment/incremental/IncrementalIndex.java","lineNumber":1048,"sourceCode":"        this.type = valueType.toString();\n      } else if (valueType.is(ValueType.COMPLEX)) {\n        ComplexMetricSerde serde = ComplexMetrics.getSerdeForType(valueType.getComplexTypeName());\n        if (serde == null) {\n          throw new ISE(\"Unable to handle complex type[%s]\", valueType);\n        }\n        this.type = serde.getTypeName();\n        // The serde's type name represents the canonical storage type (e.g., \"HLLSketch\"),\n        // while the aggregator's intermediate type may be more specific (e.g., \"HLLSketchBuild\").\n        // Using the serde's type ensures that segment metadata queries return consistent types\n        // across realtime (IncrementalIndex) and historical (QueryableIndex) segments.\n        // See https://github.com/apache/druid/issues/14315.\n        capabilities = ColumnCapabilitiesImpl.createDefault()\n                                             .setType(ColumnType.ofComplex(serde.getTypeName()))\n                                             .setHasNulls(ColumnCapabilities.Capable.TRUE);\n      } else {\n        // if we need to handle non-numeric and non-complex types (e.g. strings, arrays) it should be done here\n        // and we should determine the appropriate ColumnCapabilities\n        throw new ISE(\"Unable to handle type[%s] for AggregatorFactory[%s]\", valueType, factory.getClass());\n      }\n    }\n\n    public int getIndex()\n    {\n      return index;\n    }\n\n    public String getName()\n    {\n      return name;\n    }\n\n    public String getType()\n    {\n      return type;\n    }\n","sourceCodeStart":1030,"sourceCodeEnd":1066,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/segment/incremental/IncrementalIndex.java#L1030-L1066","documentation":"IncrementalIndex's MetricDesc/MetricHolder capabilities logic only handles numeric and COMPLEX ValueTypes; anything else (e.g. STRING, arrays) for an AggregatorFactory's required type is rejected with this ISE. It marks an unsupported combination of aggregator output type and index capability handling.","triggerScenarios":"Constructing an IncrementalIndex with an AggregatorFactory whose getTypeName()/required type resolves to a non-numeric, non-complex ValueType (STRING or ARRAY), e.g. a custom aggregator returning strings or a misconfigured spec.","commonSituations":"Custom AggregatorFactory implementations declaring string/array intermediate types; spec errors where a dimension-style aggregator is used in metricsSpec; upgrading Druid where new ValueTypes (arrays) exist but index support is absent.","solutions":["Change the aggregator so its output type is numeric or a registered complex type","For string outputs, use a dimension plus query-time aggregation instead of an ingestion-time metric","Patch/extend IncrementalIndex capability handling if this is your own custom aggregator type"],"exampleFix":"// before: custom aggregator with typeName \"string\"\npublic String getTypeName() { return \"string\"; }\n// after: return a complex or numeric type\npublic String getTypeName() { return \"long\"; }","handlingStrategy":"validation","validationCode":"String t = factory.getTypeName();\nif (!isNumeric(t) && !isComplex(t)) throw new IllegalArgumentException(\"Bad aggregator type: \" + t);","typeGuard":null,"tryCatchPattern":"try { index.add(row); } catch (ISE e) { if (e.getMessage().contains(\"Unable to handle type\")) { /* fix aggregator */ } throw e; }","preventionTips":["Audit custom AggregatorFactory getTypeName values","Restrict metricsSpec to known aggregator types"],"tags":["aggregator","type-mismatch","ingestion"],"backgroundTag":"type-mismatch","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}