{"record":{"id":"30a4bbb1a79388f5","repo":"apache/druid","slug":"joining-against-a-multi-value-dimension-is-not-sup","errorCode":null,"errorMessage":"Joining against a multi-value dimension is not supported.","messagePattern":"Joining against a multi-value dimension is not supported\\.","errorType":"exception","errorClass":"QueryUnsupportedException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/segment/join/lookup/LookupJoinMatcher.java","lineNumber":80,"sourceCode":"        public ColumnType defaultType()\n        {\n          return ColumnType.STRING;\n        }\n\n        @Override\n        public Supplier<String> makeDimensionProcessor(DimensionSelector selector, boolean multiValue)\n        {\n          return () -> {\n            final IndexedInts row = selector.getRow();\n\n            if (row.size() == 1) {\n              return selector.lookupName(row.get(0));\n            } else if (row.size() == 0) {\n              return null;\n            } else {\n              // Multi-valued rows are not handled by the join system right now\n              // TODO: Remove when https://github.com/apache/druid/issues/9924 is done\n              throw new QueryUnsupportedException(\"Joining against a multi-value dimension is not supported.\");\n            }\n          };\n        }\n\n        @Override\n        public Supplier<String> makeFloatProcessor(BaseFloatColumnValueSelector selector)\n        {\n          return () -> selector.isNull() ? null : DimensionHandlerUtils.convertObjectToString(selector.getFloat());\n        }\n\n        @Override\n        public Supplier<String> makeDoubleProcessor(BaseDoubleColumnValueSelector selector)\n        {\n          return () -> selector.isNull() ? null : DimensionHandlerUtils.convertObjectToString(selector.getDouble());\n        }\n\n        @Override\n        public Supplier<String> makeLongProcessor(BaseLongColumnValueSelector selector)","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/segment/join/lookup/LookupJoinMatcher.java#L62-L98","documentation":"The lookup join matcher reads single values from the right-hand lookup dimension per row. If a row contains multiple values (multi-value dimension), the join system cannot produce a single key, so it throws QueryUnsupportedException. Druid does not support joining against multi-value dimensions (issue #9924).","triggerScenarios":"Executing a join (e.g. SQL join to a lookup) whose right-hand side column is a multi-value string dimension, and the matcher encounters a row with row.size() > 1.","commonSituations":"Ingested data where the lookup key column ended up multi-valued (e.g. array-like input split on a delimiter); joining on a column that was auto-detected as multi-valued.","solutions":["Flatten the multi-value column before joining (e.g. re-ingest with a single value, or use a transform/maxOf/arrayToString)","Rewrite the query to unnest or explode the multi-value rows first (e.g. UNNEST in SQL)","Change the ingestion spec so the join key column is always single-valued"],"exampleFix":"// before: join on multi-valued column 'tags'\n// after: SQL\nSELECT ... FROM t JOIN lookup ON t.country = lookup.k\n-- ensure 'country' is single-valued, e.g. via UNNEST or re-ingestion","handlingStrategy":"type-guard","validationCode":"ColumnCapabilities caps = selectorFactory.getColumnCapabilities(keyColumn);\nif (caps != null && caps.hasMultipleValues().isTrue()) throw new IllegalArgumentException(\"join key is multi-valued\");","typeGuard":"boolean isSingleValued(ColumnCapabilities caps) { return caps == null || !caps.hasMultipleValues().isTrue(); }","tryCatchPattern":"try { runJoin(query); } catch (QueryUnsupportedException e) { if (e.getMessage().contains(\"multi-value\")) { /* flatten and retry */ } }","preventionTips":["Check column capabilities (hasMultipleValues) before planning lookup joins","Flatten multi-value dimensions at ingestion with transforms or aggregator like 'maxOf'","Enable automatic multi-value flattening in your query-builder layer"],"tags":["java","join","lookup","multi-value","druid"],"backgroundTag":"unsupported-operation","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}