{"record":{"id":"4d824fa705bbc5b6","repo":"apache/druid","slug":"null-cursor-factory-found-probably-trying-to-issu-4d824f","errorCode":null,"errorMessage":"Null cursor factory found. Probably trying to issue a query against a segment being memory unmapped.","messagePattern":"Null cursor factory found\\. Probably trying to issue a query against a segment being memory unmapped\\.","errorType":"exception","errorClass":"SegmentMissingException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/query/timeseries/TimeseriesQueryEngine.java","lineNumber":97,"sourceCode":"      final @Global NonBlockingPool<ByteBuffer> bufferPool\n  )\n  {\n    this.bufferPool = bufferPool;\n  }\n\n  /**\n   * Run a single-segment, single-interval timeseries query on a particular adapter. The query must have been\n   * scoped down to a single interval before calling this method.\n   */\n  public Sequence<Result<TimeseriesResultValue>> process(\n      TimeseriesQuery query,\n      final CursorFactory cursorFactory,\n      @Nullable TimeBoundaryInspector timeBoundaryInspector,\n      @Nullable final TimeseriesQueryMetrics timeseriesQueryMetrics\n  )\n  {\n    if (cursorFactory == null) {\n      throw new SegmentMissingException(\n          \"Null cursor factory found. Probably trying to issue a query against a segment being memory unmapped.\"\n      );\n    }\n\n    final Interval interval = Iterables.getOnlyElement(query.getIntervals());\n    final Granularity gran = query.getGranularity();\n\n    final CursorHolder cursorHolder = cursorFactory.makeCursorHolder(makeCursorBuildSpec(query, timeseriesQueryMetrics));\n    if (cursorHolder.isPreAggregated()) {\n      query = query.withAggregatorSpecs(Preconditions.checkNotNull(cursorHolder.getAggregatorsForPreAggregated()));\n    }\n    try {\n      final Sequence<Result<TimeseriesResultValue>> result;\n\n      if (query.context().getVectorize().shouldVectorize(cursorHolder.canVectorize())) {\n        result = processVectorized(query, cursorHolder, timeBoundaryInspector, interval, gran);\n      } else {\n        result = processNonVectorized(query, cursorHolder, timeBoundaryInspector, interval, gran);","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/query/timeseries/TimeseriesQueryEngine.java#L79-L115","documentation":"The timeseries engine requires a non-null CursorFactory to read the segment. A null cursor factory means the segment's data was released from memory (mmap unmapped / dropped while query in flight), so Druid throws SegmentMissingException instead of failing obscurely later.","triggerScenarios":"Issuing a TimeseriesQuery against a segment that is being swapped out of memory or dropped concurrently (real-time task handoff, historical segment drop, rebalance during query).","commonSituations":"Cluster under segment-replication/rebalance churn, historicals dropping segments during rolling restarts, real-time task handing off while queries are executing, cache eviction racing with a query.","solutions":["Retry the query — the segment will be resolved from another replica or after the swap completes","Enable query retries on timeout/segment-missing in the broker (druid.broker.balancing / retry policy)","Avoid dropping/unloading segments while queries are in flight (drain queries before segment drop)","Check cluster stability: node failures, disk eviction, or aggressive segment drop policies"],"exampleFix":"// before\nSequence<Result<TimeseriesResultValue>> s = engine.process(query, null, null, null); // throws\n// after\nif (cursorFactory == null) {\n  // retry against another replica / fail gracefully with SegmentMissingException handling\n  throw new QueryInterruptedException(new ResourceLimitException(\"segment unavailable\"));\n}\nSequence<Result<TimeseriesResultValue>> s = engine.process(query, cursorFactory, null, null);","handlingStrategy":"retry","validationCode":"if (cursorFactory == null) { /* segment unavailable: retry or reroute before processing */ }","typeGuard":"static boolean segmentAvailable(@Nullable CursorFactory cf) { return cf != null; }","tryCatchPattern":"try { return engine.process(query, cursorFactory, tbi, metrics); }\ncatch (SegmentMissingException e) { return retryWithBackoff(query, 3); }","preventionTips":["Enable broker query retry on segment-missing","Drain queries before dropping segments","Monitor segment drop/handoff rates during rebalances"],"tags":["druid","segment-missing","concurrency","timeseries"],"backgroundTag":"resource-not-found","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}