apache/druid · error · IllegalArgumentException

The __time column must be selected if the results are time-o

Error message

The __time column must be selected if the results are time-ordered.

What it means

When a ScanQuery has a time-ordering ('order':'ascending'/'descending' on __time) but no user-supplied orderBy list, Druid requires __time to be among the selected columns, since results are ordered by that column. The plain IllegalArgumentException is thrown in the constructor when orderBysFromUser is null but an implicit time ordering column is missing from columns.

Source

Thrown at processing/src/main/java/org/apache/druid/query/scan/ScanQuery.java:184

            columnTypes.size()
        );
      }
    }

    final Pair<List<OrderBy>, Order> ordering = verifyAndReconcileOrdering(orderBysFromUser, orderFromUser);
    this.orderBys = Preconditions.checkNotNull(ordering.lhs);
    this.timeOrder = ordering.rhs;

    if (this.columns != null && this.columns.size() > 0) {
      // Validate orderBy. (Cannot validate when signature is empty, since that means "discover at runtime".)

      for (final OrderBy orderByColumn : this.orderBys) {
        if (!this.columns.contains(orderByColumn.getColumnName())) {
          // Error message depends on how the user originally specified ordering.
          if (orderBysFromUser != null) {
            throw new IAE("Column [%s] from 'orderBy' must also appear in 'columns'.", orderByColumn.getColumnName());
          } else {
            throw new IllegalArgumentException("The __time column must be selected if the results are time-ordered.");
          }
        }
      }
    }

    this.maxRowsQueuedForOrdering = validateAndGetMaxRowsQueuedForOrdering();
    this.maxSegmentPartitionsOrderedInMemory = validateAndGetMaxSegmentPartitionsOrderedInMemory();
  }

  /**
   * Verifies that the ordering of a query is solely determined by {@link #getTimeOrder()}. Required to actually
   * execute queries, because {@link #getOrderBys()} is not yet understood by the query engines.
   *
   * @throws IllegalStateException if the ordering is not solely determined by {@link #getTimeOrder()}
   */
  public static void verifyOrderByForNativeExecution(final ScanQuery query)
  {
    if (query.getTimeOrder() == Order.NONE && !query.getOrderBys().isEmpty()) {

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Add "__time" to the columns list
  2. Remove the 'order' property from the query
  3. Set an explicit orderBy on a column that is selected

Example fix

// before
{"queryType":"scan","columns":["country"],"order":"ascending"}
// after
{"queryType":"scan","columns":["__time","country"],"order":"ascending"}
Defensive patterns

Strategy: validation

Validate before calling

if (query.getOrder() != ScanQuery.Order.NONE && !query.getColumns().contains(ScanQuery.DRUID_TIMESTAMP_FIELD /* __time */) && query.getOrderBys().isEmpty()) {
  throw new IllegalArgumentException("time-ordered scan requires __time in columns");
}

Prevention

When it happens

Trigger: Creating a ScanQuery with getTimeOrder() != NONE (order set via 'order' field) where columns does not contain __time and the user did not pass an explicit orderBy list.

Common situations: Queries requesting time-sorted scans with a projected column list that omits __time; older clients that assumed __time was always implicitly returned.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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