apache/druid · error · IllegalStateException
Cannot handle datasource
Error message
Cannot handle datasource: %s
What it means
SinkQuerySegmentWalker serves queries only for the single datasource its sinks belong to. getQueryRunnerForSegments verifies the query's base table data source name matches the walker's datasource and throws this ISE otherwise — a sanity check that the query is targeting the table this walker is meant to handle.
Solutions
- Query only the exact datasource served by the realtime task; perform joins on the broker/historical layer, not at the sink walker
- Check that the query's base table name exactly matches the task's datasource (name/case)
- Fix broker query distribution so multi-datasource queries are not routed to single-datasource peons
Example fix
// before // SQL: SELECT ... FROM realtimeDs JOIN otherTable ... routed to realtimeDs peon -> throws // after // let broker handle joins; peon only receives single-table scans over realtimeDs
Defensive patterns
Strategy: validation
Validate before calling
if (!query.getDataSource().getTableNames().equals(Collections.singletonList(expectedDatasource))) { /* route elsewhere */ } Type guard
boolean isSingleTableQuery = query.getDataSource() instanceof TableDataSource && ((TableDataSource) query.getDataSource()).getName().equals(datasource);
Try / catch
try { return walker.getQueryRunnerForSegments(query, specs); } catch (ISE e) { log.warn("query datasource mismatch; delegating to broker"); return nextRunner.getQueryRunnerForSegments(query, specs); } Prevention
- Run joins/subqueries on broker, not at realtime sink walkers
- Verify datasource names (including case) in queries
- Ensure multi-datasource queries are not routed to single-datasource peons
When it happens
Trigger: A query whose dataSource resolves to a different base table (e.g. join of another table, lookup, subquery, or inline/query datasources) reaches a walker created for a specific datasource name.
Common situations: Broker routing a join or subquery to a realtime task's peon that only owns one datasource; SQL queries joining a realtime datasource with another table; misconfigured query routing or datasource naming mismatch (case differences).
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Cannot query dataSource locally
- Unknown operation[ ], known operations[ ]
- Unknown query type[ ].
- Was asked for a query runner but realtimeAppenderator was…
- 08001
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/30541712a8dfbf5b.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/main/java/org/apache/druid/segment/realtime/appenderator/SinkQuerySegmentWalker.java:181
holder.getVersion(),
chunk.getChunkNumber()
)
)
);
return getQueryRunnerForSegments(query, specs);
}
@Override
public <T> QueryRunner<T> getQueryRunnerForSegments(final Query<T> query, final Iterable<SegmentDescriptor> specs)
{
ExecutionVertex ev = ExecutionVertex.of(query);
// We only handle one particular dataSource. Make sure that's what we have, then ignore from here on out.
final DataSource dataSourceFromQuery = query.getDataSource();
// Sanity check: make sure the query is based on the table we're meant to handle.
if (!ev.getBaseTableDataSource().getName().equals(dataSource)) {
throw new ISE("Cannot handle datasource: %s", dataSourceFromQuery);
}
final QueryRunnerFactory<T, Query<T>> factory = conglomerate.findFactory(query);
if (factory == null) {
throw new ISE("Unknown query type[%s].", query.getClass());
}
final QueryToolChest<T, Query<T>> toolChest = factory.getToolchest();
final boolean skipIncrementalSegment = query.context().getBoolean(CONTEXT_SKIP_INCREMENTAL_SEGMENT, false);
final AtomicLong cpuTimeAccumulator = new AtomicLong(0L);
// Make sure this query type can handle the subquery, if present.
if ((dataSourceFromQuery instanceof QueryDataSource)
&& !toolChest.canPerformSubquery(((QueryDataSource) dataSourceFromQuery).getQuery())) {
throw new ISE("Cannot handle subquery: %s", dataSourceFromQuery);
}
// segmentMapFn maps each base Segment into a joined Segment if necessary.View on GitHub (pinned to 9b90983fd2)