apache/druid · error · IllegalStateException

Cannot load dimension order

Error message

Cannot load dimension order[%s] when existing index is not empty.

What it means

IncrementalIndex.loadDimensionList (via makeDimensionHandler) refuses to load a persisted dimension order when the index already contains rows. Dimension ordering can only be seeded into an empty index; applying it after rows were added would corrupt column ordering.

Solutions

  1. Only call loadDimensionList/loadDimensionIterable immediately after index creation, before any rows are added
  2. Create a new IncrementalIndex and load the dimension order into it before ingestion
  3. Reorder the code so dimension-order restoration precedes row ingestion

Example fix

// before
index.add(row);
index.loadDimensionIterable(oldOrder, oldFormats); // throws
// after
index.loadDimensionIterable(oldOrder, oldFormats);
index.add(row);
Defensive patterns

Strategy: validation

Validate before calling

if (index.numRows() != 0) throw new IllegalStateException("Restore dimension order only on an empty index");

Try / catch

try { index.loadDimensionIterable(order, formats); } catch (ISE e) { if (e.getMessage().contains("not empty")) { /* recreate index */ } throw e; }

Prevention

When it happens

Trigger: Calling loadDimensionIterable / index recovery that supplies oldDimensionOrder while numRows() != 0, e.g. re-applying dimension order to a live IncrementalIndex that has already ingested events.

Common situations: Realtime task recovery code paths, custom ingestion code that calls loadDimensionList after rows were added, or mixing results from a persisted index with an in-use index.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at processing/src/main/java/org/apache/druid/segment/incremental/IncrementalIndex.java:857

    }
  }

  /**
   * Currently called to initialize IncrementalIndex dimension order during index creation
   * Index dimension ordering could be changed to initialize from DimensionsSpec after resolution of
   * https://github.com/apache/druid/issues/2011
   *
   * @param oldDimensionOrder dimension order to initialize
   * @param oldColumnFormats  formats for the dimensions
   */
  public void loadDimensionIterable(
      Iterable<String> oldDimensionOrder,
      Map<String, ColumnFormat> oldColumnFormats
  )
  {
    synchronized (dimensionDescs) {
      if (numRows() != 0) {
        throw new ISE("Cannot load dimension order[%s] when existing index is not empty.", dimensionDescs.keySet());
      }
      for (String dim : oldDimensionOrder) {
        // Skip __time; its position is solely based on configuration at index creation time.
        if (!ColumnHolder.TIME_COLUMN_NAME.equals(dim) && dimensionDescs.get(dim) == null) {
          ColumnFormat format = oldColumnFormats.get(dim);
          addNewDimension(dim, format.getColumnHandler(dim));
        }
      }
    }
  }

  @GuardedBy("dimensionDescs")
  private DimensionDesc addNewDimension(String dim, DimensionHandler handler)
  {
    DimensionDesc desc = initDimension(dimensionDescs.size(), dim, handler);
    dimensionDescs.put(dim, desc);
    dimensionDescsList.add(desc);
    return desc;

View on GitHub (pinned to 9b90983fd2)