airbnb/epoxy · error · IllegalStateException

Diffing was already enabled

Error message

Diffing was already enabled

What it means

EpoxyAdapter.enableDiffing() throws IllegalStateException if diffHelper is already non-null, meaning enableDiffing() was called twice. The helper registers an observer; double registration would duplicate diff work and notifications, so it is disallowed.

Solutions

  1. Call enableDiffing() exactly once, in the adapter's constructor
  2. If unsure, guard the call: only call when diffHelper is not yet enabled (use a subclass flag if diffHelper is inaccessible)
  3. Remove duplicate calls in subclass constructors where the superclass already enables diffing

Example fix

// before
public MyAdapter() {
  super();
  enableDiffing(); // super already called it
}

// after
public MyAdapter() {
  super(); // superclass constructor calls enableDiffing() once
}
Defensive patterns

Strategy: validation

Validate before calling

// enable diffing only once
if (!diffingEnabled) { enableDiffing(); diffingEnabled = true; }

Prevention

When it happens

Trigger: Calling enableDiffing() more than once on the same adapter instance — e.g. in a constructor that a subclass also calls, or re-invoking it after reconfiguration.

Common situations: Base-class constructor calls enableDiffing() and a subclass constructor calls it again; developer adds the call defensively in an init path that runs repeatedly (adapter reuse/rebind).

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 airbnb/epoxy@e45bd3a61f (2026-09-13). Data as JSON: /api/errors/d126ba3828bd9c32. Report an issue: GitHub.

Appendix: source

Thrown at epoxy-adapter/src/main/java/com/airbnb/epoxy/EpoxyAdapter.java:44

   * are responsible for notifying data changes whenever this list is changed.
   */
  protected final List<EpoxyModel<?>> models = new ModelList();
  private DiffHelper diffHelper;

  @Override
  List<EpoxyModel<?>> getCurrentModels() {
    return models;
  }

  /**
   * Enables support for automatically notifying model changes via {@link #notifyModelsChanged()}.
   * If used, this should be called in the constructor, before any models are changed.
   *
   * @see #notifyModelsChanged()
   */
  protected void enableDiffing() {
    if (diffHelper != null) {
      throw new IllegalStateException("Diffing was already enabled");
    }

    if (!models.isEmpty()) {
      throw new IllegalStateException("You must enable diffing before modifying models");
    }

    if (!hasStableIds()) {
      throw new IllegalStateException("You must have stable ids to use diffing");
    }

    diffHelper = new DiffHelper(this, false);
  }

  @Override
  EpoxyModel<?> getModelForPosition(int position) {
    EpoxyModel<?> model = models.get(position);
    return model.isShown() ? model : hiddenModel;
  }

View on GitHub (pinned to e45bd3a61f)