{"record":{"id":"7abc6fdb5e8b46c2","repo":"airbnb/epoxy","slug":"you-must-enable-diffing-before-modifying-models","errorCode":null,"errorMessage":"You must enable diffing before modifying models","messagePattern":"You must enable diffing before modifying models","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"epoxy-adapter/src/main/java/com/airbnb/epoxy/EpoxyAdapter.java","lineNumber":48,"sourceCode":"\n  @Override\n  List<EpoxyModel<?>> getCurrentModels() {\n    return models;\n  }\n\n  /**\n   * Enables support for automatically notifying model changes via {@link #notifyModelsChanged()}.\n   * If used, this should be called in the constructor, before any models are changed.\n   *\n   * @see #notifyModelsChanged()\n   */\n  protected void enableDiffing() {\n    if (diffHelper != null) {\n      throw new IllegalStateException(\"Diffing was already enabled\");\n    }\n\n    if (!models.isEmpty()) {\n      throw new IllegalStateException(\"You must enable diffing before modifying models\");\n    }\n\n    if (!hasStableIds()) {\n      throw new IllegalStateException(\"You must have stable ids to use diffing\");\n    }\n\n    diffHelper = new DiffHelper(this, false);\n  }\n\n  @Override\n  EpoxyModel<?> getModelForPosition(int position) {\n    EpoxyModel<?> model = models.get(position);\n    return model.isShown() ? model : hiddenModel;\n  }\n\n  /**\n   * Intelligently notify item changes by comparing the current {@link #models} list against the\n   * previous so you don't have to micromanage notification calls yourself. This may be","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/airbnb/epoxy/blob/e45bd3a61fe3a1f130e184f5b8dcf172ab99025a/epoxy-adapter/src/main/java/com/airbnb/epoxy/EpoxyAdapter.java#L30-L66","documentation":"enableDiffing() requires the adapter's model list to be empty at the time it is called; if models were already added it throws IllegalStateException. This guarantees the diff helper starts from a known baseline before any model mutations occur.","triggerScenarios":"Adding models via addModel(s)/add() before calling enableDiffing(), or calling enableDiffing() after the adapter has been populated.","commonSituations":"Calling enableDiffing() in onAttachedToRecyclerView or a setter instead of the constructor; populating models in the constructor before enabling diffing.","solutions":["Move enableDiffing() to the first line of the adapter's constructor, before any addModel calls","Clear models (removeAllModels) only if appropriate, then enable diffing — but prefer correct ordering","Ensure no model population happens in superclass constructors before enableDiffing()"],"exampleFix":"// before\npublic MyAdapter() {\n  addModels(new HeaderModel_());\n  enableDiffing(); // throws\n}\n\n// after\npublic MyAdapter() {\n  enableDiffing();\n  addModels(new HeaderModel_());\n}","handlingStrategy":"validation","validationCode":"// enable diffing before any models are added\nif (adapter.getItemCount() == 0) { enableDiffing(); } else { throw new IllegalStateException(\"Models must be empty before enableDiffing\"); }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Make enableDiffing() the first statement of the constructor","Never populate models before enabling diffing","Avoid calling it from lifecycle callbacks that may run after population"],"tags":["android","epoxy","diffing","initialization"],"backgroundTag":"invalid-state-transition","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"}