airbnb/epoxy · error · IllegalStateException
You must enable diffing before notifying models changed
Error message
You must enable diffing before notifying models changed
What it means
EpoxyAdapter throws this IllegalStateException when notifyModelsChanged() is called while diffing has never been enabled (diffHelper is null). Diffing is an opt-in feature; without it there is no DiffHelper to compute model changes, so notifying would be incorrect. The library forces you to call enableDiffing() first.
Solutions
- Call enableDiffing() in your adapter's constructor before any model notifications occur
- Verify your adapter setup path actually runs enableDiffing() (check that it isn't gated behind a flag or skipped branch)
- Prefer migrating to EpoxyController/EpoxyRecyclerView with controllers, which manage diffing automatically
Example fix
// before
class MyAdapter extends EpoxyAdapter {
MyAdapter() { /* no enableDiffing */ }
void update() { notifyModelsChanged(); }
}
// after
class MyAdapter extends EpoxyAdapter {
MyAdapter() { enableDiffing(); }
void update() { notifyModelsChanged(); }
} Defensive patterns
Strategy: validation
Validate before calling
if (adapter.getModelPosition(model) >= 0 || adapter.getClass().isAnnotationPresent(DiffingEnabled.class)) { /* ensure enableDiffing() called in constructor */ } Try / catch
try { adapter.notifyModelsChanged(); } catch (IllegalStateException e) { adapter.enableDiffing(); adapter.notifyModelsChanged(); } Prevention
- Always call enableDiffing() as the first statement in your EpoxyAdapter subclass constructor
- Prefer EpoxyController-based APIs over manual adapter mutation
When it happens
Trigger: Calling the protected notifyModelsChanged() (directly or via helpers like insertModelBefore/insertModelAfter/getAllModelsAfter paths that rely on notifications) on an EpoxyAdapter subclass that never called enableDiffing().
Common situations: Subclassing EpoxyAdapter manually (instead of using EpoxyController) and calling model-mutation helpers that expect diffing; copying adapter code that assumes diffing was enabled in a base class or setup method that was skipped.
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
- Diffing is enabled. You should use notifyModelsChanged…
- Moving more than 1 item at a time is not supported. Number…
- Unknown type
- Two models have the same ID. ID's must be unique! Model at…
- Models must not be empty
AI-assisted analysis of airbnb/epoxy@e45bd3a61f (2026-09-13).
Data as JSON: /api/errors/96d84c50922a6616.
Report an issue: GitHub.
Appendix: source
Thrown at epoxy-adapter/src/main/java/com/airbnb/epoxy/EpoxyAdapter.java:79
return model.isShown() ? model : hiddenModel;
}
/**
* Intelligently notify item changes by comparing the current {@link #models} list against the
* previous so you don't have to micromanage notification calls yourself. This may be
* prohibitively slow for large model lists (in the hundreds), in which case consider doing
* notification calls yourself. If you use this, all your view models must implement {@link
* EpoxyModel#hashCode()} and {@link EpoxyModel#equals(Object)} to completely identify their
* state, so that changes to a model's content can be detected. Before using this you must enable
* it with {@link #enableDiffing()}, since keeping track of the model state adds extra computation
* time to all other data change notifications.
*
* @see #enableDiffing()
*/
protected void notifyModelsChanged() {
if (diffHelper == null) {
throw new IllegalStateException("You must enable diffing before notifying models changed");
}
diffHelper.notifyModelChanges();
}
/**
* Notify that the given model has had its data changed. It should only be called if the model
* retained the same position.
*/
protected void notifyModelChanged(EpoxyModel<?> model) {
notifyModelChanged(model, null);
}
/**
* Notify that the given model has had its data changed. It should only be called if the model
* retained the same position.
*/
protected void notifyModelChanged(EpoxyModel<?> model, @Nullable Object payload) {View on GitHub (pinned to e45bd3a61f)