apache/druid · error · IllegalStateException
Can only handle [ ], got [ ]
Error message
Can only handle [%s], got [%s]
What it means
SearchQueryQueryToolChest.run() only processes queries whose underlying Query is a SearchQuery; any other query type routed here throws ISE('Can only handle [%s], got [%s]'). This is an internal dispatch invariant — the toolchest is keyed to the SearchQuery class. Hitting it means a query of a different type was handed to the search toolchest, typically through misconfigured query wiring or custom code.
Solutions
- Ensure the Query passed in QueryPlus is an instance of SearchQuery
- Fix custom toolchest/runner registration so each query class maps to its own toolchest
- If wrapping queries, unwrap to the original SearchQuery before invoking run()
Example fix
// before
QueryPlus<Result<SearchResultValue>> qp = QueryPlus.wrap(someTimeseriesQuery);
searchToolChest.run(qp, responseContext);
// after
if (someQuery instanceof SearchQuery) {
searchToolChest.run(QueryPlus.wrap((Query<Result<SearchResultValue>>) someQuery), responseContext);
} Defensive patterns
Strategy: type-guard
Validate before calling
if (!(query instanceof SearchQuery)) { throw new IllegalArgumentException("search toolchest requires SearchQuery, got " + query.getClass()); } Type guard
Optional<SearchQuery> asSearchQuery(Query<?> q) { return q instanceof SearchQuery ? Optional.of((SearchQuery) q) : Optional.empty(); } Try / catch
try { return toolChest.run(queryPlus, ctx); } catch (ISE e) { if (e.getMessage().startsWith("Can only handle")) { rerouteToCorrectToolchest(); } else throw e; } Prevention
- Register each Query class with its matching QueryToolChest in custom wiring
- Never feed wrapped/foreign queries directly into the search toolchest
- Write unit tests that assert runner chains route by query class
When it happens
Trigger: Custom QueryRunner/toolchest wiring that routes non-SearchQuery objects into the search toolchest; reflection- or JSON-built queries losing their concrete type; calling run() programmatically with a wrapped or foreign Query.
Common situations: Extension code building custom query runners; testing harnesses that construct QueryPlus with the wrong query class; broker routing misconfiguration.
Understand the failure class
Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.
Related errors
- Got a [ ] which isn't a
- Unknown format [ ]
- attempt to get boolean[] null vector from string[] only…
- attempt to get double[] from string[] only scalar binding
- attempt to get long[] from string[] only scalar binding
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/33b0286fbf26ebd1.
Report an issue: GitHub.
Appendix: source
Thrown at processing/src/main/java/org/apache/druid/query/search/SearchQueryQueryToolChest.java:331
public SearchThresholdAdjustingQueryRunner(
QueryRunner<Result<SearchResultValue>> runner,
SearchQueryConfig config
)
{
this.runner = runner;
this.config = config;
}
@Override
public Sequence<Result<SearchResultValue>> run(
QueryPlus<Result<SearchResultValue>> queryPlus,
ResponseContext responseContext
)
{
Query<Result<SearchResultValue>> input = queryPlus.getQuery();
if (!(input instanceof SearchQuery)) {
throw new ISE("Can only handle [%s], got [%s]", SearchQuery.class, input.getClass());
}
final SearchQuery query = (SearchQuery) input;
if (query.getLimit() < config.getMaxSearchLimit()) {
return runner.run(queryPlus, responseContext);
}
final boolean isBySegment = query.context().isBySegment();
return Sequences.map(
runner.run(queryPlus.withQuery(query.withLimit(config.getMaxSearchLimit())), responseContext),
new Function<>()
{
@Override
public Result<SearchResultValue> apply(Result<SearchResultValue> input)
{
if (isBySegment) {
BySegmentSearchResultValue value = (BySegmentSearchResultValue) input.getValue();View on GitHub (pinned to 9b90983fd2)