{"record":{"id":"3ccf93efca25949e","repo":"airbnb/epoxy","slug":"you-cannot-call-buildmodels-directly-call-setmodels-instead","errorCode":null,"errorMessage":"You cannot call `buildModels` directly. Call `setModels` instead.","messagePattern":"You cannot call `buildModels` directly\\. Call `setModels` instead\\.","errorType":"exception","errorClass":"IllegalEpoxyUsage","httpStatus":null,"severity":"error","filePath":"epoxy-adapter/src/main/java/com/airbnb/epoxy/SimpleEpoxyController.java","lineNumber":36,"sourceCode":"    currentModels = models;\n    insideSetModels = true;\n    requestModelBuild();\n    insideSetModels = false;\n  }\n\n  @Override\n  public final void requestModelBuild() {\n    if (!insideSetModels) {\n      throw new IllegalEpoxyUsage(\n          \"You cannot call `requestModelBuild` directly. Call `setModels` instead.\");\n    }\n    super.requestModelBuild();\n  }\n\n  @Override\n  protected final void buildModels() {\n    if (!isBuildingModels()) {\n      throw new IllegalEpoxyUsage(\n          \"You cannot call `buildModels` directly. Call `setModels` instead.\");\n    }\n    add(currentModels);\n  }\n}\n","sourceCodeStart":18,"sourceCodeEnd":42,"githubUrl":"https://github.com/airbnb/epoxy/blob/e45bd3a61fe3a1f130e184f5b8dcf172ab99025a/epoxy-adapter/src/main/java/com/airbnb/epoxy/SimpleEpoxyController.java#L18-L42","documentation":"SimpleEpoxyController declares a final `buildModels()` that only forwards to `add(currentModels)` when a model build is genuinely in progress (guarded by `isBuildingModels()`). Throwing `IllegalEpoxyUsage` here catches subclasses that try to invoke `buildModels()` directly, bypassing the build lifecycle. The library requires model rebuilds to go through `setModels`/`requestModelBuild` so diffing, threading, and interruption are handled correctly. Calling it directly would build models outside the controller's state machine and corrupt adapter state.","triggerScenarios":"Calling `controller.buildModels()` directly from application code (e.g. in an activity, test, or after data changes) instead of `controller.setModels(...)` or `controller.requestModelBuild()`. It also fires if `buildModels()` is invoked while `isBuildingModels()` is false, i.e. outside an in-flight build pass.","commonSituations":"A subclass overrides `buildModels()` and a test tries to call it directly to force a build; a developer migrates from manual RecyclerView adapter code and calls `buildModels()` after updating data; someone copies controller internals into a helper that calls `buildModels()` to refresh the list.","solutions":["Replace the direct `buildModels()` call with `setModels(<your model list>)` if you already have models built.","If you want the controller to rebuild its models, call `requestModelBuild()` instead.","In tests, use `SimpleEpoxyController#setModels` or construct the models you need and set them, rather than invoking the protected `buildModels()`.","Ensure your subclass's `buildModels()` override only builds and adds models, and never calls itself or sibling instances' `buildModels()`."],"exampleFix":"// before\ncontroller.buildModels();\n\n// after\ncontroller.setModels(myModels);\n// or, to rebuild from the controller's own buildModels():\ncontroller.requestModelBuild();","handlingStrategy":"validation","validationCode":"// Never call buildModels() from app code.\n// Refresh via the public API:\nif (models != null) {\n  controller.setModels(models); // or controller.requestModelBuild()\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat `buildModels()` as a protected lifecycle hook you override, never call.","Use `setModels` when you have models, `requestModelBuild` when the controller should rebuild.","In tests, drive the controller with `setModels`/`setData` rather than the build hook."],"tags":["android","epoxy","lifecycle","illegal-usage"],"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"}