{"record":{"id":"f3769b00ea289bee","repo":"airbnb/epoxy","slug":"you-must-have-stable-ids-to-use-diffing","errorCode":null,"errorMessage":"You must have stable ids to use diffing","messagePattern":"You must have stable ids to use diffing","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"epoxy-adapter/src/main/java/com/airbnb/epoxy/EpoxyAdapter.java","lineNumber":52,"sourceCode":"  }\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\n   * prohibitively slow for large model lists (in the hundreds), in which case consider doing\n   * notification calls yourself. If you use this, all your view models must implement {@link\n   * EpoxyModel#hashCode()} and {@link EpoxyModel#equals(Object)} to completely identify their\n   * state, so that changes to a model's content can be detected. Before using this you must enable","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/airbnb/epoxy/blob/e45bd3a61fe3a1f130e184f5b8dcf172ab99025a/epoxy-adapter/src/main/java/com/airbnb/epoxy/EpoxyAdapter.java#L34-L70","documentation":"Diffing relies on RecyclerView stable IDs; enableDiffing() throws IllegalStateException when hasStableIds() is false. EpoxyAdapter sets hasStableIds true only when model ids are available, since the diff and payloads are keyed by id.","triggerScenarios":"Enabling diffing on an EpoxyAdapter without stable ids enabled (setHasStableIds(true) not in effect / models lacking ids).","commonSituations":"Custom EpoxyAdapter subclasses that override id behavior or construct the adapter in a way that skips stable-id setup; migrating a plain RecyclerView.Adapter pattern without stable ids.","solutions":["Ensure the adapter has stable ids: setHasStableIds(true) must be applied before models are used (EpoxyAdapter does this when models have ids)","Give every model a unique non-null id so stable ids are valid","Use EpoxyController / EpoxyRecyclerView instead, which handle ids and diffing automatically","If stable ids are impossible, do not use enableDiffing(); manage notifications manually"],"exampleFix":"// before\nclass MyAdapter extends EpoxyAdapter {\n  MyAdapter() { enableDiffing(); } // throws: no stable ids\n}\n\n// after\nclass MyAdapter extends EpoxyAdapter {\n  MyAdapter() {\n    setHasStableIds(true);\n    enableDiffing();\n  }\n}","handlingStrategy":"validation","validationCode":"// verify stable ids before enabling diffing\nif (!adapter.hasStableIds()) { adapter.setHasStableIds(true); }\nenableDiffing();","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Ensure setHasStableIds(true) is applied before models are shown","Give every model a unique, stable id","Prefer EpoxyController which enforces this automatically","Skip enableDiffing() entirely if stable ids are not feasible"],"tags":["android","epoxy","diffing","stable-ids"],"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"}