{"record":{"id":"4ca5af46e3906be5","repo":"apache/druid","slug":"currently-only-single-segment-datasources-are-supp","errorCode":null,"errorMessage":"Currently only single segment datasources are supported for broadcast joins, dataSource[%s] has multiple segments. Reingest the data so that it is entirely contained within a single segment to use in JOIN queries.","messagePattern":"Currently only single segment datasources are supported for broadcast joins, dataSource\\[(.+?)\\] has multiple segments\\. Reingest the data so that it is entirely contained within a single segment to use in JOIN queries\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"server/src/main/java/org/apache/druid/segment/join/BroadcastTableJoinableFactory.java","lineNumber":85,"sourceCode":"    if (!condition.canHashJoin()) {\n      return Optional.empty();\n    }\n    return getOnlyIndexedTable(dataSource).filter(IndexedTable::isCacheable).map(IndexedTable::computeCacheKey);\n  }\n\n  private Optional<ReferenceCountedIndexedTableProvider> getOnlyIndexedTable(DataSource dataSource)\n  {\n    GlobalTableDataSource broadcastDataSource = (GlobalTableDataSource) dataSource;\n    return segmentManager.getIndexedTables(broadcastDataSource).flatMap(tables -> {\n      Iterator<ReferenceCountedIndexedTableProvider> tableIterator = tables.iterator();\n      if (!tableIterator.hasNext()) {\n        return Optional.empty();\n      }\n      try {\n        return Optional.of(Iterators.getOnlyElement(tableIterator));\n      }\n      catch (IllegalArgumentException iae) {\n        throw new ISE(\n            \"Currently only single segment datasources are supported for broadcast joins, dataSource[%s] has multiple segments. Reingest the data so that it is entirely contained within a single segment to use in JOIN queries.\",\n            broadcastDataSource.getName()\n        );\n      }\n    });\n  }\n}\n","sourceCodeStart":67,"sourceCodeEnd":93,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/server/src/main/java/org/apache/druid/segment/join/BroadcastTableJoinableFactory.java#L67-L93","documentation":"Broadcast (lookup-style) joins in Druid require the right-hand datasource to be contained in exactly one segment, since the whole table must be materialized in memory on each node. When Iterators.getOnlyElement sees more than one segment, the IllegalArgumentException is translated into this ISE instructing reingestion into a single segment.","triggerScenarios":"Running a JOIN query whose broadcast side is a datasource with 2+ segments — commonly after incremental ingestion created many segments for the joined table.","commonSituations":"Joining against a time-partitioned datasource that has grown beyond one segment; enabling compaction too late; using broadcast joins in dev on datasources loaded over multiple batches.","solutions":["Reingest the datasource with partitioning that produces a single segment (e.g. partition by nothing / maxTotalRows large enough).","Compact the datasource so all rows are in one segment before joining.","Use a hash/equi-join against a different joinable source (e.g. a lookup) instead of a multi-segment broadcast table."],"exampleFix":"// before: join against datasource 'dim' with 5 segments\nJOIN fact ON fact.dimId = dim.id\n// after: reingest/compact 'dim' into 1 segment (tuningConfig maxTotalRows >= row count), then join","handlingStrategy":"validation","validationCode":"// query-time guard: ensure broadcast side has one segment\nif (dataSource instanceof TableDataSource && getSegmentCount(((TableDataSource) dataSource).getName()) > 1) {\n  throw new IllegalStateException(\"Broadcast join requires single-segment datasource\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Compact broadcast-joined datasources to a single segment before querying.","Prefer lookup tables or hash joins for large dimension tables."],"tags":["join","broadcast","segment-layout"],"backgroundTag":"unsupported-operation","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"}