{"record":{"id":"9ed070eeaf72e20b","repo":"airbnb/epoxy","slug":"you-cannot-call-requestmodelbuild-directly-call-setmodels","errorCode":null,"errorMessage":"You cannot call `requestModelBuild` directly. Call `setModels` instead.","messagePattern":"You cannot call `requestModelBuild` directly\\. Call `setModels` instead\\.","errorType":"exception","errorClass":"IllegalEpoxyUsage","httpStatus":null,"severity":"error","filePath":"epoxy-adapter/src/main/java/com/airbnb/epoxy/SimpleEpoxyController.java","lineNumber":27,"sourceCode":"public class SimpleEpoxyController extends EpoxyController {\n  private List<? extends EpoxyModel<?>> currentModels;\n  private boolean insideSetModels;\n\n  /**\n   * Set the models to add to this controller. Clears any previous models and adds this new list\n   * .\n   */\n  public void setModels(List<? extends EpoxyModel<?>> models) {\n    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":9,"sourceCodeEnd":42,"githubUrl":"https://github.com/airbnb/epoxy/blob/e45bd3a61fe3a1f130e184f5b8dcf172ab99025a/epoxy-adapter/src/main/java/com/airbnb/epoxy/SimpleEpoxyController.java#L9-L42","documentation":"SimpleEpoxyController.final requestModelBuild throws IllegalEpoxyUsage unless called from inside setModels, because with SimpleEpoxyController models are derived from a plain data list — building is triggered automatically by setModels, and a direct requestModelBuild would bypass that contract.","triggerScenarios":"Calling controller.requestModelBuild() directly from app code on a SimpleEpoxyController (outside setModels, where insideSetModels is false).","commonSituations":"Copy-pasting controller code: requestModelBuild is correct for custom EpoxyControllers but illegal for SimpleEpoxyController; reacting to data changes by manually rebuilding instead of calling setModels.","solutions":["Replace requestModelBuild() with controller.setModels(yourList) when using SimpleEpoxyController","Call setModels whenever the underlying data changes; the controller rebuilds automatically","If manual rebuilds are needed, switch to a custom EpoxyController with buildModels()"],"exampleFix":"// before\ncontroller.requestModelBuild();\n// after\ncontroller.setModels(data);\n","handlingStrategy":"validation","validationCode":"if (controller instanceof SimpleEpoxyController) {\n  controller.setModels(data); // not requestModelBuild()\n}","typeGuard":"boolean supportsDirectRebuild(EpoxyController c) { return !(c instanceof SimpleEpoxyController); }","tryCatchPattern":"try { controller.requestModelBuild(); } catch (IllegalEpoxyUsage e) { controller.setModels(currentData); }","preventionTips":["With SimpleEpoxyController always call setModels on data change","Reserve requestModelBuild for custom EpoxyControllers","Document the rebuild API of each controller type in your team","Base-class-check before calling lifecycle methods in shared code"],"tags":["android","epoxy","controller","simple-epoxy"],"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"}