airbnb/epoxy · error · IllegalEpoxyUsage

You cannot hide a model in an EpoxyController. Use `addIf`…

Error message

You cannot hide a model in an EpoxyController. Use `addIf` to conditionally add a model instead.

What it means

Models added through an EpoxyController must be shown; hiding (show(false)) is unsupported because the controller's declarative list should simply omit models that shouldn't appear. addInternal throws IllegalEpoxyUsage, directing you to addIf/addUnless for conditional addition.

Solutions

  1. Remove .show(false)/hide() and add the model only when its condition is true
  2. Use addIf(boolean, model) or model.addIf(condition, this) for conditional addition
  3. If default-shown logic hides models, restructure so the model is constructed only when it should appear

Example fix

// before
new FooterModel_().id(2).show(false).addTo(this); // crash
// after
new FooterModel_().id(2).addIf(showFooter, this);
Defensive patterns

Strategy: validation

Validate before calling

if (!model.isShown()) { /* don't add; use addIf instead */ } else { model.addTo(controller); }

Try / catch

try { model.addTo(controller); } catch (IllegalEpoxyUsage e) { model.addIf(shouldBeShown, controller); }

Prevention

When it happens

Trigger: Calling .show(false) (or hide()) on a model and then addTo(this)/addInternal inside buildModels().

Common situations: Porting adapter code where hide() was allowed; conditionally hiding a model based on a boolean instead of conditionally adding it; a helper method that sets show(false) for empty data before adding.

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

Appendix: source

Thrown at epoxy-adapter/src/main/java/com/airbnb/epoxy/EpoxyController.java:508

      add(model);
    }
  }

  /**
   * Method to actually add the model to the list being built. Should be called after all
   * validations are done.
   */
  void addInternal(EpoxyModel<?> modelToAdd) {
    assertIsBuildingModels();

    if (modelToAdd.hasDefaultId()) {
      throw new IllegalEpoxyUsage(
          "You must set an id on a model before adding it. Use the @AutoModel annotation if you "
              + "want an id to be automatically generated for you.");
    }

    if (!modelToAdd.isShown()) {
      throw new IllegalEpoxyUsage(
          "You cannot hide a model in an EpoxyController. Use `addIf` to conditionally add a "
              + "model instead.");
    }

    // The model being added may not have been staged if it wasn't mutated before it was added.
    // In that case we may have a previously staged model that still needs to be added.
    clearModelFromStaging(modelToAdd);
    modelToAdd.controllerToStageTo = null;
    modelsBeingBuilt.add(modelToAdd);
  }

  /**
   * Staging models allows them to be implicitly added after the user finishes modifying them. This
   * means that if a user has modified a model, and then moves on to modifying a different model,
   * the first model is automatically added as soon as the second model is modified.
   * <p>
   * There are some edge cases for handling models that are added without modification, or models
   * that are modified but then fail an `addIf` check.

View on GitHub (pinned to e45bd3a61f)