{"record":{"id":"977bb5132a4b47d0","repo":"airbnb/epoxy","slug":"you-should-set-a-layout-with-layout-instead-of-using-this","errorCode":null,"errorMessage":"You should set a layout with layout(...) instead of using this.","messagePattern":"You should set a layout with layout\\(\\.\\.\\.\\) instead of using this\\.","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"epoxy-adapter/src/main/java/com/airbnb/epoxy/EpoxyModelGroup.java","lineNumber":243,"sourceCode":"\n    for (int i = 0; i < modelCount; i++) {\n      callback.onModel(models.get(i), holder.getViewHolders().get(i), i);\n    }\n  }\n\n  private interface IterateModelsCallback {\n    void onModel(EpoxyModel model, EpoxyViewHolder viewHolder, int modelIndex);\n  }\n\n  @Override\n  public int getSpanSize(int totalSpanCount, int position, int itemCount) {\n    // Defaults to using the span size of the first model. Override this if you need to customize it\n    return models.get(0).spanSize(totalSpanCount, position, itemCount);\n  }\n\n  @Override\n  protected final int getDefaultLayout() {\n    throw new UnsupportedOperationException(\n        \"You should set a layout with layout(...) instead of using this.\");\n  }\n\n  @NonNull\n  public EpoxyModelGroup shouldSaveViewState(boolean shouldSaveViewState) {\n    onMutation();\n    this.shouldSaveViewState = shouldSaveViewState;\n    return this;\n  }\n\n  @Override\n  public boolean shouldSaveViewState() {\n    // By default state is saved if any of the models have saved state enabled.\n    // Override this if you need custom behavior.\n    if (shouldSaveViewState != null) {\n      return shouldSaveViewState;\n    } else {\n      return shouldSaveViewStateDefault;","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/airbnb/epoxy/blob/e45bd3a61fe3a1f130e184f5b8dcf172ab99025a/epoxy-adapter/src/main/java/com/airbnb/epoxy/EpoxyModelGroup.java#L225-L261","documentation":"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.","triggerScenarios":"Constructing or building an EpoxyModelGroup without calling layout(layoutRes), so Epoxy falls back to getDefaultLayout during view type resolution.","commonSituations":"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.","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"],"exampleFix":"// before\nnew EpoxyModelGroup_().models(models); // no layout -> throws\n// after\nnew EpoxyModelGroup_(R.layout.my_group_layout).models(models).id(groupId).addTo(this);","handlingStrategy":"validation","validationCode":"if (layoutRes == 0) throw new IllegalStateException(\"EpoxyModelGroup requires an explicit layout\");","typeGuard":null,"tryCatchPattern":"try { buildGroup(); } catch (UnsupportedOperationException e) { Log.e(TAG, \"Group built without layout\", e); }","preventionTips":["Always pass layoutRes to EpoxyModelGroup_ builder constructor","Set layout(...) immediately when constructing groups programmatically"],"tags":["android","epoxy","missing-layout","unsupported-operation"],"backgroundTag":"unsupported-operation","analyzedSha":"e45bd3a61fe3a1f130e184f5b8dcf172ab99025a","analyzedAt":"2026-09-13T03:24:16.052Z","contentChangedAt":"2026-09-13T03:24:16.052Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}