{"record":{"id":"30541712a8dfbf5b","repo":"apache/druid","slug":"cannot-handle-datasource-s-305417","errorCode":null,"errorMessage":"Cannot handle datasource: %s","messagePattern":"Cannot handle datasource: (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"server/src/main/java/org/apache/druid/segment/realtime/appenderator/SinkQuerySegmentWalker.java","lineNumber":181,"sourceCode":"                        holder.getVersion(),\n                        chunk.getChunkNumber()\n                    )\n                )\n        );\n\n    return getQueryRunnerForSegments(query, specs);\n  }\n\n  @Override\n  public <T> QueryRunner<T> getQueryRunnerForSegments(final Query<T> query, final Iterable<SegmentDescriptor> specs)\n  {\n    ExecutionVertex ev = ExecutionVertex.of(query);\n    // We only handle one particular dataSource. Make sure that's what we have, then ignore from here on out.\n    final DataSource dataSourceFromQuery = query.getDataSource();\n\n    // Sanity check: make sure the query is based on the table we're meant to handle.\n    if (!ev.getBaseTableDataSource().getName().equals(dataSource)) {\n      throw new ISE(\"Cannot handle datasource: %s\", dataSourceFromQuery);\n    }\n\n    final QueryRunnerFactory<T, Query<T>> factory = conglomerate.findFactory(query);\n    if (factory == null) {\n      throw new ISE(\"Unknown query type[%s].\", query.getClass());\n    }\n\n    final QueryToolChest<T, Query<T>> toolChest = factory.getToolchest();\n    final boolean skipIncrementalSegment = query.context().getBoolean(CONTEXT_SKIP_INCREMENTAL_SEGMENT, false);\n    final AtomicLong cpuTimeAccumulator = new AtomicLong(0L);\n\n    // Make sure this query type can handle the subquery, if present.\n    if ((dataSourceFromQuery instanceof QueryDataSource)\n        && !toolChest.canPerformSubquery(((QueryDataSource) dataSourceFromQuery).getQuery())) {\n      throw new ISE(\"Cannot handle subquery: %s\", dataSourceFromQuery);\n    }\n\n    // segmentMapFn maps each base Segment into a joined Segment if necessary.","sourceCodeStart":163,"sourceCodeEnd":199,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/server/src/main/java/org/apache/druid/segment/realtime/appenderator/SinkQuerySegmentWalker.java#L163-L199","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","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"],"exampleFix":"// before\n// SQL: SELECT ... FROM realtimeDs JOIN otherTable ...  routed to realtimeDs peon -> throws\n// after\n// let broker handle joins; peon only receives single-table scans over realtimeDs","handlingStrategy":"validation","validationCode":"if (!query.getDataSource().getTableNames().equals(Collections.singletonList(expectedDatasource))) { /* route elsewhere */ }","typeGuard":"boolean isSingleTableQuery = query.getDataSource() instanceof TableDataSource && ((TableDataSource) query.getDataSource()).getName().equals(datasource);","tryCatchPattern":"try { return walker.getQueryRunnerForSegments(query, specs); } catch (ISE e) { log.warn(\"query datasource mismatch; delegating to broker\"); return nextRunner.getQueryRunnerForSegments(query, specs); }","preventionTips":["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"],"tags":["java","query","datasource"],"backgroundTag":"invalid-argument-value","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"}