apache/druid · error · SegmentMissingException

Null cursor factory found. Probably trying to issue a query

Error message

Null cursor factory found. Probably trying to issue a query against a segment being memory unmapped.

What it means

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.

Source

Thrown at processing/src/main/java/org/apache/druid/query/topn/TopNQueryEngine.java:87

  {
    this.bufferPool = bufferPool;
  }

  /**
   * Do the thing - process a {@link Segment} into a {@link Sequence} of {@link TopNResultValue}, with one of the
   * fine {@link TopNAlgorithm} available chosen based on the type of column being aggregated. The algorithm provides a
   * mapping function to process rows from the adapter {@link Cursor} to apply {@link AggregatorFactory} and create or
   * update {@link TopNResultValue}
   */
  public Sequence<Result<TopNResultValue>> query(
      TopNQuery query,
      final Segment segment,
      @Nullable final TopNQueryMetrics queryMetrics
  )
  {
    final CursorFactory cursorFactory = segment.as(CursorFactory.class);
    if (cursorFactory == null) {
      throw new SegmentMissingException(
          "Null cursor factory found. Probably trying to issue a query against a segment being memory unmapped."
      );
    }

    final CursorBuildSpec buildSpec = makeCursorBuildSpec(query, queryMetrics);
    final CursorHolder cursorHolder = cursorFactory.makeCursorHolder(buildSpec);

    // Once we have a cursorHolder, we need to either return a Sequence, or close it immediately.
    try {
      if (cursorHolder.isPreAggregated()) {
        query = query.withAggregatorSpecs(Preconditions.checkNotNull(cursorHolder.getAggregatorsForPreAggregated()));
      }
      final Cursor cursor = cursorHolder.asCursor();
      if (cursor == null) {
        return Sequences.withBaggage(Sequences.empty(), cursorHolder);
      }

      final TimeBoundaryInspector timeBoundaryInspector = segment.as(TimeBoundaryInspector.class);

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Retry the query — Druid clusters normally route to a live replica and the transient unmap resolves
  2. Verify the segment still exists on the coordinator and is served by a historical node
  3. Check historical logs for segment drop/handoff storms; tune druid.server.http numThreads / unmap caching
  4. If reproducible on a specific segment type, query a datasource/segment backed by a cursor-capable adapter

Example fix

// before
Segment segment = dataSourceView.get(segmentId); // may be unmapped
queryEngine.query(query, segment, null); // throws SegmentMissingException
// after
try {
  queryEngine.query(query, segment, null);
} catch (SegmentMissingException e) {
  // retry against refreshed segment/replica
}
Defensive patterns

Strategy: retry

Validate before calling

CursorFactory cursorFactory = segment.as(CursorFactory.class);
if (cursorFactory == null) { /* segment missing; refresh segment reference and retry */ }

Type guard

boolean isQueryable(Segment segment) {
  return segment != null && segment.as(CursorFactory.class) != null;
}

Try / catch

try {
  return topNQueryEngine.query(query, segment, metrics);
} catch (SegmentMissingException e) {
  // segment unmapped; retry via broker or reload segment reference
  return retryQuery(query);
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/7a11f3ffb6fcb250. Report an issue: GitHub.