airbnb/epoxy · error · IllegalStateException

Models must not be empty

Error message

Models must not be empty

What it means

DiffPayload's package-private constructor requires a non-empty list of changed models; an empty list throws IllegalStateException. Payloads describe the old versions of models for a change notification, so an empty list means nothing changed and no payload should be created.

Solutions

  1. Skip creating a payload when the changed-models list is empty (emit plain notifyItemRangeChanged instead)
  2. Use stock epoxy versions rather than forks that may pass empty lists
  3. In tests, never build DiffPayload with an empty list; assert models before constructing

Example fix

// before
new DiffPayload(Collections.emptyList()); // throws

// after
if (!models.isEmpty()) {
  new DiffPayload(models);
}
Defensive patterns

Strategy: validation

Validate before calling

// only create a payload when there is at least one model
if (models.isEmpty()) return;
new DiffPayload(models);

Prevention

When it happens

Trigger: Constructing DiffPayload with an empty List<EpoxyModel<?>> — only reachable via onItemRangeChanged in DiffHelper passing a payload list with no models, or via direct construction in the same package/tests.

Common situations: Modified/forked DiffHelper code that adds empty payload lists for change notifications; test code building DiffPayload directly; library-internal edge cases on stock code are not expected to hit this.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at epoxy-adapter/src/main/java/com/airbnb/epoxy/DiffPayload.java:22

import java.util.List;

import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.collection.LongSparseArray;

/**
 * A helper class for tracking changed models found by the {@link com.airbnb.epoxy.DiffHelper} to
 * be included as a payload in the
 * {@link androidx.recyclerview.widget.RecyclerView.Adapter#notifyItemChanged(int, Object)}
 * call.
 */
public class DiffPayload {
  private final EpoxyModel<?> singleModel;
  private final LongSparseArray<EpoxyModel<?>> modelsById;

  DiffPayload(List<? extends EpoxyModel<?>> models) {
    if (models.isEmpty()) {
      throw new IllegalStateException("Models must not be empty");
    }

    int modelCount = models.size();

    if (modelCount == 1) {
      // Optimize for the common case of only one model changed.
      singleModel = models.get(0);
      modelsById = null;
    } else {
      singleModel = null;
      modelsById = new LongSparseArray<>(modelCount);
      for (EpoxyModel<?> model : models) {
        modelsById.put(model.id(), model);
      }
    }
  }

  public DiffPayload(EpoxyModel<?> changedItem) {

View on GitHub (pinned to e45bd3a61f)