{"record":{"id":"1180f664e23f6e6f","repo":"airbnb/epoxy","slug":"cannot-call-requestdelayedmodelbuild-from-inside-buildmodels","errorCode":null,"errorMessage":"Cannot call `requestDelayedModelBuild` from inside `buildModels`","messagePattern":"Cannot call `requestDelayedModelBuild` from inside `buildModels`","errorType":"exception","errorClass":"IllegalEpoxyUsage","httpStatus":null,"severity":"error","filePath":"epoxy-adapter/src/main/java/com/airbnb/epoxy/EpoxyController.java","lineNumber":225,"sourceCode":"   * <p>\n   * Using this to delay a model update may be helpful in cases where user input is causing many\n   * rapid changes in the models, such as typing. In that case, the view is already updated on\n   * screen and constantly rebuilding models is potentially slow and unnecessary. The downside to\n   * delaying the model build too long is that models will not be in sync with the data or view, and\n   * scrolling the view offscreen and back onscreen will cause the model to bind old data.\n   * <p>\n   * If a previous request is still pending it will be removed in favor of this new delay\n   * <p>\n   * Any call to {@link #requestModelBuild()} will override a delayed request.\n   * <p>\n   * In most cases you should use {@link #requestModelBuild()} instead of this.\n   *\n   * @param delayMs The time in milliseconds to delay the model build by. Should be greater than or\n   *                equal to 0. A value of 0 is equivalent to calling {@link #requestModelBuild()}\n   */\n  public synchronized void requestDelayedModelBuild(int delayMs) {\n    if (isBuildingModels()) {\n      throw new IllegalEpoxyUsage(\n          \"Cannot call `requestDelayedModelBuild` from inside `buildModels`\");\n    }\n\n    if (requestedModelBuildType == RequestedModelBuildType.DELAYED) {\n      cancelPendingModelBuild();\n    } else if (requestedModelBuildType == RequestedModelBuildType.NEXT_FRAME) {\n      return;\n    }\n\n    requestedModelBuildType =\n        delayMs == 0 ? RequestedModelBuildType.NEXT_FRAME : RequestedModelBuildType.DELAYED;\n\n    modelBuildHandler.postDelayed(buildModelsRunnable, delayMs);\n  }\n\n  /**\n   * Cancels a pending call to {@link #buildModels()} if one has been queued by {@link\n   * #requestModelBuild()}.","sourceCodeStart":207,"sourceCodeEnd":243,"githubUrl":"https://github.com/airbnb/epoxy/blob/e45bd3a61fe3a1f130e184f5b8dcf172ab99025a/epoxy-adapter/src/main/java/com/airbnb/epoxy/EpoxyController.java#L207-L243","documentation":"requestDelayedModelBuild(delayMs) schedules a debounced buildModels() pass; invoking it while buildModels() is already running would queue a build inside the build being executed, so an IllegalEpoxyUsage is thrown. Like requestModelBuild, it must be called outside model building.","triggerScenarios":"Calling requestDelayedModelBuild() (directly, or via moveModel) from within buildModels().","commonSituations":"Scheduling a delayed refresh from inside buildModels; calling controller.moveModel(...) during building instead of outside it; chaining a delayed build from logic invoked by buildModels.","solutions":["Call requestDelayedModelBuild() only outside buildModels (e.g. after data updates)","Replace in-build scheduling with addModelBuildListener + post-build request","If using moveModel, ensure it is invoked outside the buildModels pass"],"exampleFix":"// before\n@Override\nprotected void buildModels() {\n  requestDelayedModelBuild(100); // crash\n  ...\n}\n// after\nvoid onDataChanged() {\n  requestDelayedModelBuild(100);\n}\n@Override\nprotected void buildModels() { ... }","handlingStrategy":"try-catch","validationCode":"if (!controller.isBuildingModels()) { controller.requestDelayedModelBuild(delayMs); }","typeGuard":null,"tryCatchPattern":"try { controller.requestDelayedModelBuild(100); } catch (IllegalEpoxyUsage e) { /* defer until after current build */ }","preventionTips":["Schedule delayed builds from data-update paths, never inside buildModels","Call moveModel outside of the building pass"],"tags":["android","epoxy","reentrancy","illegal-usage"],"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"}