{"record":{"id":"626f1103139a7b14","repo":"airbnb/epoxy","slug":"this-model-was-already-added-to-the-controller-at-position","errorCode":null,"errorMessage":"This model was already added to the controller at position {position}","messagePattern":"This model was already added to the controller at position (.+?)","errorType":"exception","errorClass":"IllegalEpoxyUsage","httpStatus":null,"severity":"error","filePath":"epoxy-adapter/src/main/java/com/airbnb/epoxy/EpoxyModel.java","lineNumber":418,"sourceCode":"\n  /**\n   * @see #addIf(AddPredicate, EpoxyController)\n   */\n  public interface AddPredicate {\n    boolean addIf();\n  }\n\n  /**\n   * This is used internally by generated models to turn on validation checking when\n   * \"validateEpoxyModelUsage\" is enabled and the model is used with an {@link EpoxyController}.\n   */\n  protected final void addWithDebugValidation(@NonNull EpoxyController controller) {\n    if (controller == null) {\n      throw new IllegalArgumentException(\"Controller cannot be null\");\n    }\n\n    if (controller.isModelAddedMultipleTimes(this)) {\n      throw new IllegalEpoxyUsage(\n          \"This model was already added to the controller at position \"\n              + controller.getFirstIndexOfModelInBuildingList(this));\n    }\n\n    if (firstControllerAddedTo == null) {\n      firstControllerAddedTo = controller;\n\n      // We save the current hashCode so we can compare it to the hashCode at later points in time\n      // in order to validate that it doesn't change and enforce mutability.\n      hashCodeWhenAdded = hashCode();\n\n      // The one time it is valid to change the model is during an interceptor callback. To support\n      // that we need to update the hashCode after interceptors have been run.\n      // The model can be added to multiple controllers, but we only allow an interceptor change\n      // the first time, since after that it will have been added to an adapter.\n      controller.addAfterInterceptorCallback(new ModelInterceptorCallback() {\n        @Override\n        public void onInterceptorsStarted(EpoxyController controller) {","sourceCodeStart":400,"sourceCodeEnd":436,"githubUrl":"https://github.com/airbnb/epoxy/blob/e45bd3a61fe3a1f130e184f5b8dcf172ab99025a/epoxy-adapter/src/main/java/com/airbnb/epoxy/EpoxyModel.java#L400-L436","documentation":"Each model instance can be added to a controller only once, because ids must be unique for diffing. When debug validation is enabled and the model is detected a second time in the controller's building list, Epoxy throws IllegalEpoxyUsage naming the first position it was added.","triggerScenarios":"Adding the same EpoxyModel instance twice in buildModels (e.g. appending it to the list twice, or reusing one instance variable for multiple list items).","commonSituations":"Reusing a single field model for each item of a list instead of creating a new instance per item; accidentally calling add() on the model twice; adding a model to two lists that both get built.","solutions":["Create a new model instance for each item (e.g. in a loop: new ItemModel_().id(item.getId()))","Remove the duplicate add of the same instance","Give reused models distinct ids and build them fresh each pass","Keep model construction inside buildModels instead of caching shared instances"],"exampleFix":"// before\nItemModel_ item = new ItemModel_();\nfor (Data d : list) { item.id(d.id); item.add(); } // same instance twice\n// after\nfor (Data d : list) { new ItemModel_().id(d.id).addTo(this); }","handlingStrategy":"validation","validationCode":"if (buildingModels.contains(model)) throw new IllegalStateException(\"Model added twice: \" + model);","typeGuard":null,"tryCatchPattern":"try { buildModelsInternal(); } catch (IllegalEpoxyUsage e) { Log.e(TAG, \"Duplicate model add\", e); }","preventionTips":["Create a new model instance per item in loops","Never reuse a single model field for multiple list entries","Build models fresh each buildModels pass"],"tags":["android","epoxy","duplicate-model","validation"],"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"}