airbnb/epoxy · error · IllegalArgumentException

Moving more than 1 item at a time is not supported. Number…

Error message

Moving more than 1 item at a time is not supported. Number of items moved: {itemCount}

What it means

DiffHelper's move handling only supports single-item moves; when onItemRangeMoved receives itemCount != 1 it throws IllegalArgumentException. Multi-item moves cannot be applied to the internal ModelState list with the simple remove/re-add logic used here.

Solutions

  1. Emit one notifyItemMoved(from, to) per moved item instead of a range move
  2. Perform multi-item reorders via notifyModelsChanged() so the diff computes them
  3. Reorder the model list yourself and let the diff detect the changes
  4. Split the move into a remove+insert pair if single-move emission is impossible

Example fix

// before
adapter.notifyItemRangeMoved(from, to, 3); // throws in DiffHelper

// after
for (int i = 0; i < 3; i++) {
  adapter.notifyItemMoved(from + i, to + i);
}
Defensive patterns

Strategy: validation

Validate before calling

// emit single-item moves only
if (itemCount == 1) { adapter.notifyItemMoved(fromPosition, toPosition); }

Prevention

When it happens

Trigger: A move notification with more than one item (notifyItemRangeMoved with itemCount > 1, or AdapterListUpdateCallback batching a multi-element drag move) reaches the DiffHelper observer.

Common situations: Drag-and-drop reordering libraries (e.g. ItemTouchHelper with multi-selection) that move several items and coalesce them into one range-move notification; custom adapters emitting range moves.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of airbnb/epoxy@e45bd3a61f (2026-09-13). Data as JSON: /api/errors/7def93f572576896. Report an issue: GitHub.

Appendix: source

Thrown at epoxy-adapter/src/main/java/com/airbnb/epoxy/DiffHelper.java:104

      }
      modelsToRemove.clear();

      // Update positions of affected items
      int size = currentStateList.size();
      for (int i = positionStart; i < size; i++) {
        currentStateList.get(i).position -= itemCount;
      }
    }

    @Override
    public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
      if (fromPosition == toPosition) {
        // no-op
        return;
      }

      if (itemCount != 1) {
        throw new IllegalArgumentException("Moving more than 1 item at a time is not "
            + "supported. Number of items moved: " + itemCount);
      }

      ModelState model = currentStateList.remove(fromPosition);
      model.position = toPosition;
      currentStateList.add(toPosition, model);

      if (fromPosition < toPosition) {
        // shift the affected items left
        for (int i = fromPosition; i < toPosition; i++) {
          currentStateList.get(i).position--;
        }
      } else {
        // shift the affected items right
        for (int i = toPosition + 1; i <= fromPosition; i++) {
          currentStateList.get(i).position++;
        }
      }

View on GitHub (pinned to e45bd3a61f)