airbnb/epoxy · error · UnsupportedOperationException
Diffing is enabled. You should use notifyModelsChanged…
Error message
Diffing is enabled. You should use notifyModelsChanged instead of notifyDataSetChanged
What it means
When diffing is enabled, DiffHelper registers an AdapterDataObserver whose onChanged() throws UnsupportedOperationException. This catches calls to notifyDataSetChanged(), which would wipe RecyclerView's animation state and defeat the purpose of diffing. You must use notifyModelsChanged() instead, which runs the diff and emits granular notifications.
Solutions
- Replace notifyDataSetChanged() with notifyModelsChanged() on the EpoxyAdapter
- Remove or gate any framework/library code paths that call notifyDataSetChanged()
- Call notifyItemChanged/Inserted/Removed for single-item updates instead
- If blanket notification is truly needed, do not enable diffing on that adapter
Example fix
// before adapter.notifyDataSetChanged(); // after adapter.notifyModelsChanged();
Defensive patterns
Strategy: validation
Validate before calling
// avoid the throwing call when diffing is on
if (!adapter.isDiffingEnabled()) { adapter.notifyDataSetChanged(); } else { adapter.notifyModelsChanged(); } Try / catch
// if third-party code may call it
try {
adapter.notifyDataSetChanged();
} catch (UnsupportedOperationException e) {
adapter.notifyModelsChanged();
} Prevention
- Standardize on notifyModelsChanged() in codebases with diffing adapters
- Grep for notifyDataSetChanged in diffing-enabled screens
- Wrap legacy notification helpers behind one adapter-facing API
When it happens
Trigger: Calling adapter.notifyDataSetChanged() (directly or via RecyclerView helpers) on an EpoxyAdapter that has called enableDiffing().
Common situations: Copy-pasted RecyclerView code calling notifyDataSetChanged() after setModels(); Paging or SwipeRefresh callbacks that blanket-notify; upgrading from a non-diffing adapter to enableDiffing() without removing legacy notifyDataSetChanged calls.
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
- 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
- Diffing was already enabled
AI-assisted analysis of airbnb/epoxy@e45bd3a61f (2026-09-13).
Data as JSON: /api/errors/756e256ddd0c38ce.
Report an issue: GitHub.
Appendix: source
Thrown at epoxy-adapter/src/main/java/com/airbnb/epoxy/DiffHelper.java:36
// Using a HashMap instead of a LongSparseArray to
// have faster look up times at the expense of memory
private Map<Long, ModelState> oldStateMap = new HashMap<>();
private ArrayList<ModelState> currentStateList = new ArrayList<>();
private Map<Long, ModelState> currentStateMap = new HashMap<>();
private final BaseEpoxyAdapter adapter;
private final boolean immutableModels;
DiffHelper(BaseEpoxyAdapter adapter, boolean immutableModels) {
this.adapter = adapter;
this.immutableModels = immutableModels;
adapter.registerAdapterDataObserver(observer);
}
private final RecyclerView.AdapterDataObserver observer = new RecyclerView.AdapterDataObserver() {
@Override
public void onChanged() {
throw new UnsupportedOperationException(
"Diffing is enabled. You should use notifyModelsChanged instead of notifyDataSetChanged");
}
@Override
public void onItemRangeChanged(int positionStart, int itemCount) {
for (int i = positionStart; i < positionStart + itemCount; i++) {
currentStateList.get(i).hashCode = adapter.getCurrentModels().get(i).hashCode();
}
}
@Override
public void onItemRangeInserted(int positionStart, int itemCount) {
if (itemCount == 0) {
// no-op
return;
}
if (itemCount == 1 || positionStart == currentStateList.size()) {View on GitHub (pinned to e45bd3a61f)