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
- Ensure the dataSources JSON array has at least one datasource
- 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
- 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
- Drop empty branches before constructing a union
- Validate query JSON dataSources array before submission
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
- Cannot deserialize type
- Cannot handle dataSource
- Cannot hide column
- Cannot specify DESC clustering key
- Different restrictions on table
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)