airbnb/epoxy · error · IllegalStateException

Models were set with #setModels, they can not be rebuilt.

Error message

Models were set with #setModels, they can not be rebuilt.

What it means

EpoxyRecyclerView.requestModelBuild() cannot rebuild models when the controller is a SimpleEpoxyController created internally by setModels — its models were supplied explicitly and there is no build callback to re-run. Attempting this throws this IllegalStateException.

Solutions

  1. Re-call recyclerView.setModels(newModels) with a freshly built list
  2. Switch to recyclerView.withModels { ... } so requestModelBuild has a rebuild callback
  3. If using a TypedEpoxyController, call setData on the controller instead

Example fix

// before
recyclerView.setModels(models);
recyclerView.requestModelBuild(); // throws
// after
recyclerView.setModels(buildModelList()); // rebuild by re-setting models
Defensive patterns

Strategy: validation

Validate before calling

val controller = recyclerView.epoxyController
if (controller != null && controller !is SimpleEpoxyController) recyclerView.requestModelBuild() else recyclerView.setModels(buildModelList())

Type guard

fun canRebuild(rv: EpoxyRecyclerView) = rv.epoxyController != null && rv.epoxyController !is SimpleEpoxyController

Try / catch

try { recyclerView.requestModelBuild() } catch (e: IllegalStateException) { recyclerView.setModels(buildModelList()) }

Prevention

When it happens

Trigger: Calling recyclerView.requestModelBuild() after models were set via recyclerView.setModels(...) (or modelsWithConstructors), which internally uses a SimpleEpoxyController.

Common situations: Mixing setModels usage with requestModelBuild for refresh; assuming requestModelBuild works universally like with controller-based setups.

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/7ab8ec559d8ed2f9. Report an issue: GitHub.

Appendix: source

Thrown at epoxy-adapter/src/main/java/com/airbnb/epoxy/EpoxyRecyclerView.kt:539

         */
        fun buildModels(controller: EpoxyController)
    }

    /**
     * Request that the currently set EpoxyController has its models rebuilt. You can use this to
     * avoid saving your controller as a field.
     *
     * You cannot use this if your controller is a [TypedEpoxyController] or if you set
     * models via [setModels]. In that case you must set data directly on the
     * controller or set models again.
     */
    fun requestModelBuild() {
        if (epoxyController == null) {
            throw IllegalStateException("A controller must be set before requesting a model build.")
        }

        if (epoxyController is SimpleEpoxyController) {
            throw IllegalStateException("Models were set with #setModels, they can not be rebuilt.")
        }

        epoxyController!!.requestModelBuild()
    }

    /**
     * Clear the currently set EpoxyController or Adapter as well as any models that are displayed.
     *
     * Any pending requests to the EpoxyController to build models are canceled.
     *
     * Any existing child views are recycled to the view pool.
     */
    open fun clear() {
        // The controller is cleared so the next time models are set we can create a fresh one.
        epoxyController?.cancelPendingModelBuild()
        epoxyController = null

        // We use swapAdapter instead of setAdapter so that the view pool is not cleared.

View on GitHub (pinned to e45bd3a61f)