{"record":{"id":"3f3abc8d1f0843ea","repo":"apache/druid","slug":"cannot-handle-subquery-s-3f3abc","errorCode":null,"errorMessage":"Cannot handle subquery: %s","messagePattern":"Cannot handle subquery: (.+?)","errorType":"http","errorClass":"QueryUnsupportedException","httpStatus":500,"severity":"error","filePath":"server/src/main/java/org/apache/druid/server/ServerManager.java","lineNumber":584,"sourceCode":"      final QueryUnsupportedException e = new QueryUnsupportedException(\n          StringUtils.format(\"Unknown query type, [%s]\", query.getClass())\n      );\n      log.makeAlert(e, \"Error while executing a query[%s]\", query.getId())\n         .addData(\"dataSource\", dataSourceFromQuery)\n         .emit();\n      throw e;\n    }\n    return factory;\n  }\n\n  protected static <T> QueryToolChest<T, Query<T>> getQueryToolChest(Query<T> query, QueryRunnerFactory<T, Query<T>> factory)\n  {\n    final DataSource dataSourceFromQuery = query.getDataSource();\n    final QueryToolChest<T, Query<T>> toolChest = factory.getToolchest();\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 QueryUnsupportedException(StringUtils.format(\"Cannot handle subquery: %s\", dataSourceFromQuery));\n    }\n    return toolChest;\n  }\n\n  /**\n   * {@link QueryRunner} that on run builds a set of {@link QueryRunner} for a set of {@link SegmentDescriptor} and\n   * merges them using the {@link QueryToolChest}. The {@link VersionedIntervalTimeline} provides segment references,\n   * which are registered with a closer as they are acquired, and then released in the baggage of merged result\n   * {@link Sequence}\n   */\n  public class ResourceManagingQueryRunner<T> implements QueryRunner<T>\n  {\n    private final VersionedIntervalTimeline<String, DataSegment> timeline;\n    private final QueryRunnerFactory<T, Query<T>> factory;\n    private final QueryToolChest<T, Query<T>> toolChest;\n    private final ExecutionVertex ev;\n    private final Iterable<SegmentDescriptor> specs;\n","sourceCodeStart":566,"sourceCodeEnd":602,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/server/src/main/java/org/apache/druid/server/ServerManager.java#L566-L602","documentation":"ServerManager.buildQueryToolChest (getQueryToolChest) verifies that the query's QueryToolChest supports subqueries via canPerformSubquery. If the top-level query's dataSource is a QueryDataSource (subquery) and the toolchest cannot perform subqueries, it throws QueryUnsupportedException naming the dataSource.","triggerScenarios":"Running a native query whose dataSource is another query on a query type that lacks subquery support (e.g. some extension query types like topN/scan variants historically, or custom query types) against the broker.","commonSituations":"Wrapping an unsupported query type inside a native groupBy/scan subquery; custom extension queries used as subqueries; older versions where certain query types did not implement canPerformSubquery.","solutions":["Rewrite the query so the outer query does not take a QueryDataSource (e.g. run subquery separately, or use SQL which plans supported subqueries)","Use a query type that supports subqueries (groupBy, timeseries, scan) as the outer query","Upgrade Druid if the subquery support was added for that query type in later releases","If using a custom query type, implement canPerformSubquery in its QueryToolChest"],"exampleFix":"// before\nGroupByQuery.builder().setDataSource(new QueryDataSource(topNQuery))...\n// after\n// run the subquery first and use its results via SQL or a table/inline datasource\nclient.run(subQuery); // then build outer query against materialized results","handlingStrategy":"try-catch","validationCode":"DataSource ds = query.getDataSource();\nif (ds instanceof QueryDataSource\n    && !factory.getToolchest().canPerformSubquery(((QueryDataSource) ds).getQuery())) {\n  throw new UnsupportedOperationException(\"Query type cannot handle subquery: \" + ds);\n}","typeGuard":"boolean supportsSubquery(QueryToolChest<?, ?> chest, Query<?> q) {\n  return !(q.getDataSource() instanceof QueryDataSource)\n      || chest.canPerformSubquery(((QueryDataSource) q.getDataSource()).getQuery());\n}","tryCatchPattern":"try {\n  return serverManager.buildQueryRunner(...);\n} catch (QueryUnsupportedException e) {\n  if (e.getMessage().startsWith(\"Cannot handle subquery\")) {\n    log.warn(\"Query type does not support subqueries: %s\", e.getMessage());\n  }\n  throw e;\n}","preventionTips":["Check toolChest.canPerformSubquery before building nested native queries","Prefer SQL (which plans supported subqueries) over hand-built nested native queries","Use groupBy/timeseries/scan as outer query types when nesting","Keep extension query types out of subquery position unless they implement canPerformSubquery"],"tags":["query","subquery","native-query","unsupported"],"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"}