{"record":{"id":"76bd228b3b1e9611","repo":"apache/druid","slug":"was-asked-for-a-query-runner-but-realtimeappendera","errorCode":null,"errorMessage":"Was asked for a query runner but realtimeAppenderator was null!","messagePattern":"Was asked for a query runner but realtimeAppenderator was null!","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"server/src/main/java/org/apache/druid/segment/realtime/appenderator/PeonAppenderatorsManager.java","lineNumber":174,"sourceCode":"      );\n      return batchAppenderator;\n    }\n  }\n\n  @Override\n  public void removeAppenderatorsForTask(String taskId, String dataSource)\n  {\n    // the peon only runs one task, and the process will shutdown later, don't need to do anything\n  }\n\n  @Override\n  public <T> QueryRunner<T> getQueryRunnerForIntervals(\n      Query<T> query,\n      Iterable<Interval> intervals\n  )\n  {\n    if (realtimeAppenderator == null) {\n      throw new ISE(\"Was asked for a query runner but realtimeAppenderator was null!\");\n    } else {\n      return realtimeAppenderator.getQueryRunnerForIntervals(query, intervals);\n    }\n  }\n\n  @Override\n  public <T> QueryRunner<T> getQueryRunnerForSegments(\n      Query<T> query,\n      Iterable<SegmentDescriptor> specs\n  )\n  {\n    if (realtimeAppenderator == null) {\n      throw new ISE(\"Was asked for a query runner but realtimeAppenderator was null!\");\n    } else {\n      return realtimeAppenderator.getQueryRunnerForSegments(query, specs);\n    }\n  }\n","sourceCodeStart":156,"sourceCodeEnd":192,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/server/src/main/java/org/apache/druid/segment/realtime/appenderator/PeonAppenderatorsManager.java#L156-L192","documentation":"getQueryRunnerForIntervals can only serve queries through the single realtime appenderator of the peon. If it is null (no realtime appenderator was created, e.g. in a batch task), the manager throws this ISE because it cannot answer queries from in-flight data.","triggerScenarios":"Issuing a query against a peon that has only a batch appenderator, or before createRealtimeAppenderatorForTask has run; query routing (QueryLifecycle / broker) hitting this QueryableDataSource during batch ingestion.","commonSituations":"Querying in-flight data of a batch task; querying a datasource whose only peon has shut down its appenderator; misdirected broker query routing to a batch task's peon.","solutions":["Only query datasources being served by a realtime (streaming) task","Ensure createRealtimeAppenderatorForTask is invoked before any query arrives at the peon","Wait for batch task segments to be published and query historical/middle-manager-published data instead"],"exampleFix":"// before\nQueryRunner<T> runner = peonManager.getQueryRunnerForIntervals(query, intervals); // throws if batch\n// after\nif (taskTypeSupportsRealtimeQuery(task)) {\n  QueryRunner<T> runner = peonManager.getQueryRunnerForIntervals(query, intervals);\n}","handlingStrategy":"validation","validationCode":"if (!isRealtimeTask(task)) { return null; /* skip peon query */ }","typeGuard":"if (manager.hasRealtimeAppenderator()) { runner = manager.getQueryRunnerForIntervals(q, intervals); }","tryCatchPattern":"try { return manager.getQueryRunnerForIntervals(query, intervals); } catch (ISE e) { log.warn(\"no realtime appenderator; no in-flight data\"); return null; }","preventionTips":["Only route queries to streaming tasks' peons","Create the realtime appenderator before advertising the task as queryable","Query batch data only after segments are published"],"tags":["java","query","appenderator"],"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"}