airbnb/epoxy · error · UnsupportedOperationException
You should set a layout with layout(...) instead of using…
Error message
You should set a layout with layout(...) instead of using this.
What it means
Unlike most models, EpoxyModelGroup has no default layout — a layout must be supplied explicitly, since the group's purpose is to bind multiple models into a given layout. getDefaultLayout is therefore final and always throws UnsupportedOperationException to enforce this at construction time.
Solutions
- Always pass a layout resource to the group (e.g. EpoxyModelGroup_(R.layout.group_layout) or layout(R.layout.group_layout))
- Set the layout before the model is added in buildModels
- Do not subclass EpoxyModelGroup expecting to override getDefaultLayout — it is final
Example fix
// before new EpoxyModelGroup_().models(models); // no layout -> throws // after new EpoxyModelGroup_(R.layout.my_group_layout).models(models).id(groupId).addTo(this);
Defensive patterns
Strategy: validation
Validate before calling
if (layoutRes == 0) throw new IllegalStateException("EpoxyModelGroup requires an explicit layout"); Try / catch
try { buildGroup(); } catch (UnsupportedOperationException e) { Log.e(TAG, "Group built without layout", e); } Prevention
- Always pass layoutRes to EpoxyModelGroup_ builder constructor
- Set layout(...) immediately when constructing groups programmatically
When it happens
Trigger: Constructing or building an EpoxyModelGroup without calling layout(layoutRes), so Epoxy falls back to getDefaultLayout during view type resolution.
Common situations: Forgetting the layout parameter in the group builder; migrating code from a normal model (which has a default layout) to a group; programmatically constructing EpoxyModelGroup with a missing layout argument path.
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
- Layout resources are unsupported. Views must be created…
- UnboundedViewPool does not support setting a maximum number…
- Must have stable ids when saving view holder state
- State cannot be restored once views have been bound. It…
- Tried to restore instance state, but onSaveInstanceState…
AI-assisted analysis of airbnb/epoxy@e45bd3a61f (2026-09-13).
Data as JSON: /api/errors/977bb5132a4b47d0.
Report an issue: GitHub.
Appendix: source
Thrown at epoxy-adapter/src/main/java/com/airbnb/epoxy/EpoxyModelGroup.java:243
for (int i = 0; i < modelCount; i++) {
callback.onModel(models.get(i), holder.getViewHolders().get(i), i);
}
}
private interface IterateModelsCallback {
void onModel(EpoxyModel model, EpoxyViewHolder viewHolder, int modelIndex);
}
@Override
public int getSpanSize(int totalSpanCount, int position, int itemCount) {
// Defaults to using the span size of the first model. Override this if you need to customize it
return models.get(0).spanSize(totalSpanCount, position, itemCount);
}
@Override
protected final int getDefaultLayout() {
throw new UnsupportedOperationException(
"You should set a layout with layout(...) instead of using this.");
}
@NonNull
public EpoxyModelGroup shouldSaveViewState(boolean shouldSaveViewState) {
onMutation();
this.shouldSaveViewState = shouldSaveViewState;
return this;
}
@Override
public boolean shouldSaveViewState() {
// By default state is saved if any of the models have saved state enabled.
// Override this if you need custom behavior.
if (shouldSaveViewState != null) {
return shouldSaveViewState;
} else {
return shouldSaveViewStateDefault;View on GitHub (pinned to e45bd3a61f)