airbnb/epoxy · error · IllegalStateException

Model is not added

Error message

Model is not added: {model}

What it means

getAllModelsAfter(model) requires the given model to exist in the models list (documented via @param model Must exist in {@link #models}). When getModelPosition(model) returns -1 the sublist cannot be computed, so an IllegalStateException "Model is not added" is thrown.

Solutions

  1. Verify the anchor model is present (getModelPosition(model) != -1) before calling
  2. Ensure the anchor model is added unconditionally or guard the call behind the same condition that adds it
  3. Re-acquire the model reference from the adapter instead of holding stale instances across updates

Example fix

// before
adapter.hideAllAfterModel(myHeader);
// after
if (adapter.getModelPosition(myHeader) != -1) {
  adapter.hideAllAfterModel(myHeader);
}
Defensive patterns

Strategy: validation

Validate before calling

if (adapter.getModelPosition(model) != -1) { List<EpoxyModel<?>> after = adapter.getAllModelsAfter(model); }

Try / catch

try { adapter.hideAllAfterModel(model); } catch (IllegalStateException e) { /* anchor missing; skip or rebuild list */ }

Prevention

When it happens

Trigger: Calling getAllModelsAfter (directly, or via hideAllAfterModel/modelsToRemove) with a model that is not currently in the adapter's models list.

Common situations: hideAllAfterModel on a model that was conditionally not added; a stale model reference after a clearModels(); diffing-based updates removing the anchor before the helper runs.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


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

Appendix: source

Thrown at epoxy-adapter/src/main/java/com/airbnb/epoxy/EpoxyAdapter.java:342

   * Hides all models currently located after the given model in the {@link #models} list.
   *
   * @param model The model after which to hide. It must exist in the {@link #models} list.
   */
  protected void hideAllAfterModel(EpoxyModel<?> model) {
    hideModels(getAllModelsAfter(model));
  }

  /**
   * Returns a sub list of all items in {@link #models} that occur after the given model. This list
   * is backed by the original models list, any changes to the returned list will be reflected in
   * the original {@link #models} list.
   *
   * @param model Must exist in {@link #models}.
   */
  protected List<EpoxyModel<?>> getAllModelsAfter(EpoxyModel<?> model) {
    int index = getModelPosition(model);
    if (index == -1) {
      throw new IllegalStateException("Model is not added: " + model);
    }
    return models.subList(index + 1, models.size());
  }

  /**
   * We pause the list's notifications when we modify models internally, since we already do the
   * proper adapter notifications for those modifications. By pausing these list notifications we
   * prevent the differ having to do work to track them.
   */
  private void pauseModelListNotifications() {
    ((ModelList) models).pauseNotifications();
  }

  private void resumeModelListNotifications() {
    ((ModelList) models).resumeNotifications();
  }
}

View on GitHub (pinned to e45bd3a61f)