{"record":{"id":"7a11f3ffb6fcb250","repo":"apache/druid","slug":"null-cursor-factory-found-probably-trying-to-issu-7a11f3","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/topn/TopNQueryEngine.java","lineNumber":87,"sourceCode":"  {\n    this.bufferPool = bufferPool;\n  }\n\n  /**\n   * Do the thing - process a {@link Segment} into a {@link Sequence} of {@link TopNResultValue}, with one of the\n   * fine {@link TopNAlgorithm} available chosen based on the type of column being aggregated. The algorithm provides a\n   * mapping function to process rows from the adapter {@link Cursor} to apply {@link AggregatorFactory} and create or\n   * update {@link TopNResultValue}\n   */\n  public Sequence<Result<TopNResultValue>> query(\n      TopNQuery query,\n      final Segment segment,\n      @Nullable final TopNQueryMetrics queryMetrics\n  )\n  {\n    final CursorFactory cursorFactory = segment.as(CursorFactory.class);\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 CursorBuildSpec buildSpec = makeCursorBuildSpec(query, queryMetrics);\n    final CursorHolder cursorHolder = cursorFactory.makeCursorHolder(buildSpec);\n\n    // Once we have a cursorHolder, we need to either return a Sequence, or close it immediately.\n    try {\n      if (cursorHolder.isPreAggregated()) {\n        query = query.withAggregatorSpecs(Preconditions.checkNotNull(cursorHolder.getAggregatorsForPreAggregated()));\n      }\n      final Cursor cursor = cursorHolder.asCursor();\n      if (cursor == null) {\n        return Sequences.withBaggage(Sequences.empty(), cursorHolder);\n      }\n\n      final TimeBoundaryInspector timeBoundaryInspector = segment.as(TimeBoundaryInspector.class);","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/query/topn/TopNQueryEngine.java#L69-L105","documentation":"TopNQueryEngine.query obtains a CursorFactory from the segment via segment.as(CursorFactory.class). A null result means the underlying segment (often a memory-mapped/MMappedIndex) has been released/unmapped, so query execution cannot proceed; Druid throws SegmentMissingException to signal the segment is gone and the query should be retried against a valid segment.","triggerScenarios":"Issuing a topN query while the historical node is dropping or swapping the segment — memory unmapping races with query execution; also when querying a segment type that cannot adapt to CursorFactory (e.g. a metadata-only or realtime segment without cursor support).","commonSituations":"Historical server under segment load/replication balancing unmaps segments during queries; query sent to a druid node already closing the segment after a segment-handoff; hitting a 'zombie' realtime task segment being shut down.","solutions":["Retry the query — Druid clusters normally route to a live replica and the transient unmap resolves","Verify the segment still exists on the coordinator and is served by a historical node","Check historical logs for segment drop/handoff storms; tune druid.server.http numThreads / unmap caching","If reproducible on a specific segment type, query a datasource/segment backed by a cursor-capable adapter"],"exampleFix":"// before\nSegment segment = dataSourceView.get(segmentId); // may be unmapped\nqueryEngine.query(query, segment, null); // throws SegmentMissingException\n// after\ntry {\n  queryEngine.query(query, segment, null);\n} catch (SegmentMissingException e) {\n  // retry against refreshed segment/replica\n}","handlingStrategy":"retry","validationCode":"CursorFactory cursorFactory = segment.as(CursorFactory.class);\nif (cursorFactory == null) { /* segment missing; refresh segment reference and retry */ }","typeGuard":"boolean isQueryable(Segment segment) {\n  return segment != null && segment.as(CursorFactory.class) != null;\n}","tryCatchPattern":"try {\n  return topNQueryEngine.query(query, segment, metrics);\n} catch (SegmentMissingException e) {\n  // segment unmapped; retry via broker or reload segment reference\n  return retryQuery(query);\n}","preventionTips":["Route queries through the broker so it retries on live replicas","Avoid holding Segment references across long delays; re-fetch before querying","Monitor historical nodes for segment unmap/handoff churn","Pin query execution away from segments scheduled for dropping via coordinator rules"],"tags":["query","topn","segment-missing","race-condition","druid"],"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-14T05:17:10.506Z"}