apache/druid · error · IllegalStateException

'dataSources' must be non-null and non-empty for 'union'

Error message

'dataSources' must be non-null and non-empty for 'union'

What it means

UnionDataSource's @JsonCreator constructor requires a non-null, non-empty dataSources list; a union of zero sources is meaningless and Druid throws ISE during deserialization or direct construction. This is an eager constructor guard so invalid unions never enter the query tree.

Solutions

  1. Ensure the dataSources JSON array has at least one datasource
  2. In query-building code, check the list is non-empty before constructing the union, else fall back to the single source or skip the union
  3. Validate query JSON before submitting

Example fix

// before
return new UnionDataSource(collectedSources); // collectedSources may be empty
// after
if (collectedSources.size() == 1) {
  return collectedSources.get(0);
} else if (collectedSources.isEmpty()) {
  throw new IAE("No datasources to union");
}
return new UnionDataSource(collectedSources);
Defensive patterns

Strategy: validation

Validate before calling

if (dataSources == null || dataSources.isEmpty()) {
  throw new IllegalArgumentException("Union requires at least one datasource");
}
new UnionDataSource(dataSources);

Type guard

boolean isUnionConstructible(List<DataSource> ds) {
  return ds != null && !ds.isEmpty();
}

Try / catch

try {
  DataSource u = new UnionDataSource(dataSources);
} catch (IllegalStateException e) {
  // fall back to single datasource or reject query
}

Prevention

When it happens

Trigger: Deserializing JSON {"type":"union","dataSources":[]} or null dataSources; programmatically calling new UnionDataSource(emptyList) after filtering out all sources from a union.

Common situations: Query-building code that collects sub-datasources into a list, all of which were filtered out, leaving an empty list; hand-written query JSON missing the dataSources array.

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

Appendix: source

Thrown at processing/src/main/java/org/apache/druid/query/UnionDataSource.java:55

 * <p>
 * Native engine can only work with table datasources that are scans or simple mappings (column rename without any
 * expression applied on top). Therefore, it uses methods like {@link #getTableNames()} and
 * {@link #isTableBased()} to assert that the children were TableDataSources.
 * <p>
 * MSQ should be able to plan and work with arbitrary datasources.  It also needs to replace the datasource with the
 * InputNumberDataSource while preparing the query plan.
 */
public class UnionDataSource implements DataSource
{

  @JsonProperty("dataSources")
  private final List<DataSource> dataSources;

  @JsonCreator
  public UnionDataSource(@JsonProperty("dataSources") List<DataSource> dataSources)
  {
    if (dataSources == null || dataSources.isEmpty()) {
      throw new ISE("'dataSources' must be non-null and non-empty for 'union'");
    }

    this.dataSources = dataSources;
  }

  /**
   * Asserts that the children of the union are all table data sources before returning the table names
   */
  @Override
  public Set<String> getTableNames()
  {
    if (!isTableBased()) {
      throw DruidException.defensive("contains non-table based datasource");
    }
    return dataSources
        .stream()
        .map(DataSource::getTableNames)
        .flatMap(Set::stream)

View on GitHub (pinned to 9b90983fd2)