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

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.

Source

Thrown at processing/src/main/java/org/apache/druid/query/timeseries/TimeseriesQueryEngine.java:97

      final @Global NonBlockingPool<ByteBuffer> bufferPool
  )
  {
    this.bufferPool = bufferPool;
  }

  /**
   * Run a single-segment, single-interval timeseries query on a particular adapter. The query must have been
   * scoped down to a single interval before calling this method.
   */
  public Sequence<Result<TimeseriesResultValue>> process(
      TimeseriesQuery query,
      final CursorFactory cursorFactory,
      @Nullable TimeBoundaryInspector timeBoundaryInspector,
      @Nullable final TimeseriesQueryMetrics timeseriesQueryMetrics
  )
  {
    if (cursorFactory == null) {
      throw new SegmentMissingException(
          "Null cursor factory found. Probably trying to issue a query against a segment being memory unmapped."
      );
    }

    final Interval interval = Iterables.getOnlyElement(query.getIntervals());
    final Granularity gran = query.getGranularity();

    final CursorHolder cursorHolder = cursorFactory.makeCursorHolder(makeCursorBuildSpec(query, timeseriesQueryMetrics));
    if (cursorHolder.isPreAggregated()) {
      query = query.withAggregatorSpecs(Preconditions.checkNotNull(cursorHolder.getAggregatorsForPreAggregated()));
    }
    try {
      final Sequence<Result<TimeseriesResultValue>> result;

      if (query.context().getVectorize().shouldVectorize(cursorHolder.canVectorize())) {
        result = processVectorized(query, cursorHolder, timeBoundaryInspector, interval, gran);
      } else {
        result = processNonVectorized(query, cursorHolder, timeBoundaryInspector, interval, gran);

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Retry the query — the segment will be resolved from another replica or after the swap completes
  2. Enable query retries on timeout/segment-missing in the broker (druid.broker.balancing / retry policy)
  3. Avoid dropping/unloading segments while queries are in flight (drain queries before segment drop)
  4. Check cluster stability: node failures, disk eviction, or aggressive segment drop policies

Example fix

// before
Sequence<Result<TimeseriesResultValue>> s = engine.process(query, null, null, null); // throws
// after
if (cursorFactory == null) {
  // retry against another replica / fail gracefully with SegmentMissingException handling
  throw new QueryInterruptedException(new ResourceLimitException("segment unavailable"));
}
Sequence<Result<TimeseriesResultValue>> s = engine.process(query, cursorFactory, null, null);
Defensive patterns

Strategy: retry

Validate before calling

if (cursorFactory == null) { /* segment unavailable: retry or reroute before processing */ }

Type guard

static boolean segmentAvailable(@Nullable CursorFactory cf) { return cf != null; }

Try / catch

try { return engine.process(query, cursorFactory, tbi, metrics); }
catch (SegmentMissingException e) { return retryWithBackoff(query, 3); }

Prevention

When it happens

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

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

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/4d824fa705bbc5b6. Report an issue: GitHub.