{"record":{"id":"a8003457d9acc6d3","repo":"apache/druid","slug":"cannot-load-dimension-order-s-when-existing-inde","errorCode":null,"errorMessage":"Cannot load dimension order[%s] when existing index is not empty.","messagePattern":"Cannot load dimension order\\[(.+?)\\] when existing index is not empty\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/segment/incremental/IncrementalIndex.java","lineNumber":857,"sourceCode":"    }\n  }\n\n  /**\n   * Currently called to initialize IncrementalIndex dimension order during index creation\n   * Index dimension ordering could be changed to initialize from DimensionsSpec after resolution of\n   * https://github.com/apache/druid/issues/2011\n   *\n   * @param oldDimensionOrder dimension order to initialize\n   * @param oldColumnFormats  formats for the dimensions\n   */\n  public void loadDimensionIterable(\n      Iterable<String> oldDimensionOrder,\n      Map<String, ColumnFormat> oldColumnFormats\n  )\n  {\n    synchronized (dimensionDescs) {\n      if (numRows() != 0) {\n        throw new ISE(\"Cannot load dimension order[%s] when existing index is not empty.\", dimensionDescs.keySet());\n      }\n      for (String dim : oldDimensionOrder) {\n        // Skip __time; its position is solely based on configuration at index creation time.\n        if (!ColumnHolder.TIME_COLUMN_NAME.equals(dim) && dimensionDescs.get(dim) == null) {\n          ColumnFormat format = oldColumnFormats.get(dim);\n          addNewDimension(dim, format.getColumnHandler(dim));\n        }\n      }\n    }\n  }\n\n  @GuardedBy(\"dimensionDescs\")\n  private DimensionDesc addNewDimension(String dim, DimensionHandler handler)\n  {\n    DimensionDesc desc = initDimension(dimensionDescs.size(), dim, handler);\n    dimensionDescs.put(dim, desc);\n    dimensionDescsList.add(desc);\n    return desc;","sourceCodeStart":839,"sourceCodeEnd":875,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/segment/incremental/IncrementalIndex.java#L839-L875","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Only call loadDimensionList/loadDimensionIterable immediately after index creation, before any rows are added","Create a new IncrementalIndex and load the dimension order into it before ingestion","Reorder the code so dimension-order restoration precedes row ingestion"],"exampleFix":"// before\nindex.add(row);\nindex.loadDimensionIterable(oldOrder, oldFormats); // throws\n// after\nindex.loadDimensionIterable(oldOrder, oldFormats);\nindex.add(row);","handlingStrategy":"validation","validationCode":"if (index.numRows() != 0) throw new IllegalStateException(\"Restore dimension order only on an empty index\");","typeGuard":null,"tryCatchPattern":"try { index.loadDimensionIterable(order, formats); } catch (ISE e) { if (e.getMessage().contains(\"not empty\")) { /* recreate index */ } throw e; }","preventionTips":["Order all schema-loading calls before first add()","Test recovery paths with non-empty indexes"],"tags":["ingestion","dimension-order","state"],"backgroundTag":"invalid-state-transition","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}