{"record":{"id":"5f98bb272d35c333","repo":"apache/druid","slug":"got-a-s-which-isn-t-a-s-5f98bb","errorCode":null,"errorMessage":"Got a [%s] which isn't a %s","messagePattern":"Got a \\[(.+?)\\] which isn't a (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/query/timeboundary/TimeBoundaryQueryRunnerFactory.java","lineNumber":117,"sourceCode":"    @Nullable\n    private final TimeBoundaryInspector timeBoundaryInspector;\n\n    public TimeBoundaryQueryRunner(Segment segment)\n    {\n      this.cursorFactory = segment.as(CursorFactory.class);\n      this.dataInterval = segment.getDataInterval();\n      this.timeBoundaryInspector = segment.as(TimeBoundaryInspector.class);\n    }\n\n    @Override\n    public Sequence<Result<TimeBoundaryResultValue>> run(\n        final QueryPlus<Result<TimeBoundaryResultValue>> queryPlus,\n        final ResponseContext responseContext\n    )\n    {\n      Query<Result<TimeBoundaryResultValue>> input = queryPlus.getQuery();\n      if (!(input instanceof TimeBoundaryQuery)) {\n        throw new ISE(\"Got a [%s] which isn't a %s\", input.getClass(), TimeBoundaryQuery.class);\n      }\n\n      final TimeBoundaryQuery query = (TimeBoundaryQuery) input;\n\n      return new BaseSequence<>(\n          new BaseSequence.IteratorMaker<>()\n          {\n            @Override\n            public Iterator<Result<TimeBoundaryResultValue>> make()\n            {\n              if (cursorFactory == null) {\n                throw new ISE(\n                    \"Null cursor factory found. Probably trying to issue a query against a segment being memory unmapped.\"\n                );\n              }\n\n              DateTime minTime = null;\n              DateTime maxTime = null;","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/query/timeboundary/TimeBoundaryQueryRunnerFactory.java#L99-L135","documentation":"TimeBoundaryQueryRunnerFactory's QueryRunner.run() checks that the incoming QueryPlus actually wraps a TimeBoundaryQuery before executing it against the segment, throwing an IllegalStateException (ISE) if not. This is an internal contract check: timeboundary runners are registered only for TimeBoundaryQuery, so receiving any other query type means a dispatcher/registry bug or a misconstructed runner chain. The message includes the offending query class and the expected class.","triggerScenarios":"Calling run() on a TimeBoundaryQueryRunnerFactory-created runner with a QueryPlus whose query is not a TimeBoundaryQuery, e.g. a query of another type being routed to the timeboundary runner via a misconfigured QueryRunnerFactoryConglomerate or custom segment walker.","commonSituations":"Custom query tooling building runner chains manually and pairing the wrong factory with a query; plugins or tests registering the timeboundary factory for other query types; segment walkers returning runners in the wrong order so a foreign query hits the wrong runner.","solutions":["Ensure the query routed to this runner is a TimeBoundaryQuery (queryType 'timeBoundary')","Check the QueryRunnerFactoryConglomerate/SegmentWalker wiring so each query type maps to its own factory","If using custom code, verify the query class before obtaining the runner from the conglomerate","Update or remove any custom QueryRunnerFactory registrations that handle foreign query types"],"exampleFix":"// before\nQueryRunner<Result<TimeBoundaryResultValue>> runner = factory.createRunner(segment);\nrunner.run(QueryPlus.wrap(scanQuery), responseContext); // ISE\n// after\nif (query instanceof TimeBoundaryQuery) {\n  runner.run(QueryPlus.wrap(query), responseContext);\n} else {\n  runner = conglomerate.getRunner(query, segment);\n}","handlingStrategy":"type-guard","validationCode":"if (!(query instanceof TimeBoundaryQuery)) {\n  throw new IllegalArgumentException(\"timeboundary runner requires a TimeBoundaryQuery, got \" + query.getClass());\n}","typeGuard":"boolean isTimeBoundaryQuery(Query<?> q) {\n  return q instanceof org.apache.druid.query.timeboundary.TimeBoundaryQuery;\n}","tryCatchPattern":"try {\n  return runner.run(QueryPlus.wrap(query), responseContext);\n} catch (IllegalStateException e) {\n  if (e.getMessage() != null && e.getMessage().startsWith(\"Got a [\")) {\n    // wrong runner for this query type: re-route via conglomerate\n    return conglomerate.getRunner(query, segment).run(QueryPlus.wrap(query), responseContext);\n  }\n  throw e;\n}","preventionTips":["Obtain runners from QueryRunnerFactoryConglomerate instead of hand-wiring factories","Keep custom SegmentWalker code type-dispatched per query class","Verify factory registrations when writing Druid extensions","Assert query types in tests that exercise custom runner chains"],"tags":["druid","internal-error","query-routing","type-mismatch"],"backgroundTag":"internal-invariant-violation","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}