airbnb/epoxy · error · IllegalStateException

You cannot call `buildModels` directly. Call `setData`…

Error message

You cannot call `buildModels` directly. Call `setData` instead to trigger a model refresh with new data.

What it means

Typed4EpoxyController implements buildModels() as final and only allows it to run while an internal model build (started by setData) is in progress. Calling it yourself from outside that flow throws this IllegalStateException. It exists to force users to supply data via setData instead of building models manually.

Solutions

  1. Replace the direct buildModels() call with controller.setData(d1, d2, d3, d4)
  2. Move your data update so the controller's setData overload is the single entry point that triggers the rebuild
  3. If a delayed build is needed, use setData with the typed data rather than requestDelayedModelBuild

Example fix

// before
controller.buildModels();
// after
controller.setData(data1, data2, data3, data4);
Defensive patterns

Strategy: validation

Validate before calling

if (controller is Typed4EpoxyController) { controller.setData(d1, d2, d3, d4); } else { controller.buildModels(); }

Type guard

fun isTyped4Controller(c: EpoxyController) = c is Typed4EpoxyController<*,*,*,*>

Prevention

When it happens

Trigger: Calling controller.buildModels() directly on a Typed4EpoxyController subclass from application code, so isBuildingModels() is false at that moment.

Common situations: Migrating code from a plain EpoxyController (where buildModels is the override point) to a TypedEpoxyController and keeping an explicit buildModels() call; calling buildModels after updating data manually instead of using setData.

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


AI-assisted analysis of airbnb/epoxy@e45bd3a61f (2026-09-13). Data as JSON: /api/errors/00edbe7cce1af5aa. Report an issue: GitHub.

Appendix: source

Thrown at epoxy-adapter/src/main/java/com/airbnb/epoxy/Typed4EpoxyController.java:78

    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 "
              + "model refresh with new data.");
    }
    super.requestDelayedModelBuild(delayMs);
  }

  @Override
  protected final void buildModels() {
    if (!isBuildingModels()) {
      throw new IllegalStateException(
          "You cannot call `buildModels` directly. Call `setData` instead to trigger a model "
              + "refresh with new data.");
    }
    buildModels(data1, data2, data3, data4);
  }

  protected abstract void buildModels(T data1, U data2, V data3, W data4);
}

View on GitHub (pinned to e45bd3a61f)