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

Typed4EpoxyController finalizes `requestModelBuild()` and throws `IllegalStateException` unless `allowModelBuildRequests` is true, which is only the case transiently inside `setData(data1, data2, data3, data4)`. This enforces the Typed-controller contract: model rebuilds always accompany fresh data so all four data fields and the models stay in sync.

Solutions

  1. Call `controller.setData(newData1, newData2, newData3, newData4)` with all four current values.
  2. Keep the authoritative data in the owning screen and re-submit the full tuple on every change.
  3. Use base `EpoxyController` if manual rebuild control is genuinely needed.
  4. Make `buildModels(data1, data2, data3, data4)` depend only on its parameters so re-submission is idempotent.

Example fix

// before
controller.requestModelBuild(); // IllegalStateException

// after
controller.setData(latestData1, latestData2, latestData3, latestData4);
Defensive patterns

Strategy: validation

Validate before calling

// Typed4EpoxyController: refresh only via setData
controller.setData(newData1, newData2, newData3, newData4);

Prevention

When it happens

Trigger: Calling `controller.requestModelBuild()` directly, e.g. after mutating one of the four data objects in place or after an async update, instead of calling `setData` with new values.

Common situations: Porting refresh logic from plain `EpoxyController` to a Typed4 controller; pushing only some of the four data pieces and hoping a rebuild picks them up; triggering rebuilds from a presenter after network callbacks.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

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

  /**
   * Call this with the latest data when you want models to be rebuilt. The data will be passed on
   * to {@link #buildModels(Object, Object, Object, Object)}
   */
  public void setData(T data1, U data2, V data3, W data4) {
    this.data1 = data1;
    this.data2 = data2;
    this.data3 = data3;
    this.data4 = data4;
    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)