airbnb/epoxy · error · IllegalStateException
You cannot call `requestModelBuild` directly. Call…
Error message
You cannot call `requestModelBuild` directly. Call `setData` instead to trigger a model refresh with new data.
What it means
TypedEpoxyController disables direct requestModelBuild() calls after setup: models are rebuilt only when setData is called. Calling requestModelBuild() from outside the internal flow throws this IllegalStateException to enforce data-driven model building.
Solutions
- Call controller.setData(data) instead of requestModelBuild()
- If you need requestModelBuild semantics, use a plain EpoxyController or SimpleEpoxyController rather than a Typed one
Example fix
// before controller.requestModelBuild(); // after controller.setData(newData);
Defensive patterns
Strategy: validation
Validate before calling
if (controller is TypedEpoxyController<*>) controller.setData(data) else controller.requestModelBuild()
Type guard
fun isTypedController(c: EpoxyController) = c is TypedEpoxyController<*>
Prevention
- Route all refresh calls through setData for typed controllers
- Document that TypedEpoxyController is data-driven only
- Add lint/arch checks banning requestModelBuild on typed controllers
When it happens
Trigger: Calling controller.requestModelBuild() on a TypedEpoxyController after construction, when allowModelBuildRequests has been set to false.
Common situations: Calling requestModelBuild from an Activity/Fragment after data changes instead of calling setData; copying EpoxyController usage patterns onto a TypedEpoxyController subclass.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- You cannot call `buildModels` directly. Call `setData`…
- You cannot call `buildModels` directly. Call `setData`…
- A controller must be set before requesting a model build.
- Models were set with #setModels, they can not be rebuilt.
- You must enable diffing before notifying models changed
AI-assisted analysis of airbnb/epoxy@e45bd3a61f (2026-09-13).
Data as JSON: /api/errors/bfaedf2d1ffc9832.
Report an issue: GitHub.
Appendix: source
Thrown at epoxy-adapter/src/main/java/com/airbnb/epoxy/TypedEpoxyController.java:41
public TypedEpoxyController() {
}
public TypedEpoxyController(Handler modelBuildingHandler, Handler diffingHandler) {
super(modelBuildingHandler, diffingHandler);
}
public final void setData(T data) {
currentData = data;
allowModelBuildRequests = true;
requestModelBuild();
allowModelBuildRequests = false;
}
@Override
public final void requestModelBuild() {
if (!allowModelBuildRequests) {
throw new IllegalStateException(
"You cannot call `requestModelBuild` directly. Call `setData` instead to trigger a "
+ "model refresh with new data.");
}
super.requestModelBuild();
}
@Override
public void moveModel(int fromPosition, int toPosition) {
allowModelBuildRequests = true;
super.moveModel(fromPosition, toPosition);
allowModelBuildRequests = false;
}
@Override
public void requestDelayedModelBuild(int delayMs) {
if (!allowModelBuildRequests) {
throw new IllegalStateException(
"You cannot call `requestModelBuild` directly. Call `setData` instead to trigger a "View on GitHub (pinned to e45bd3a61f)