airbnb/epoxy · error · IllegalArgumentException

Models cannot be empty

Error message

Models cannot be empty

What it means

An EpoxyModelGroup wraps a set of models and binds them into one layout; with zero models there is nothing to bind and no id to inherit (it takes the id of the first model), so the private constructor throws IllegalArgumentException for an empty list.

Solutions

  1. Check that the list is non-empty before constructing the group, or skip adding the group entirely
  2. Add a placeholder/empty-state model instead of an empty group
  3. Guard builder code paths that construct groups from dynamic data

Example fix

// before
add(new EpoxyModelGroup_(R.layout.group).models(subList)); // throws when empty
// after
if (!subList.isEmpty()) { add(new EpoxyModelGroup_(R.layout.group).models(subList)); }
Defensive patterns

Strategy: validation

Validate before calling

if (models == null || models.isEmpty()) { return; } // skip group

Type guard

if (!(models instanceof List) || ((List<?>) models).isEmpty()) return;

Try / catch

try { add(new EpoxyModelGroup_(layout).models(models)); } catch (IllegalArgumentException e) { Log.w(TAG, "Empty group skipped"); }

Prevention

When it happens

Trigger: Constructing an EpoxyModelGroup (or using withModels builders that delegate to it) with an empty List<EpoxyModel<?>>.

Common situations: Building groups from filtered/empty data lists without checking size; grouping sub-lists where a page may return zero items.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at epoxy-adapter/src/main/java/com/airbnb/epoxy/EpoxyModelGroup.java:93

  public EpoxyModelGroup(@LayoutRes int layoutRes, Collection<? extends EpoxyModel<?>> models) {
    this(layoutRes, new ArrayList<>(models));
  }

  /**
   * @param layoutRes The layout to use with these models.
   * @param models    The models that will be used to bind the views in the given layout.
   */
  public EpoxyModelGroup(@LayoutRes int layoutRes, EpoxyModel<?>... models) {
    this(layoutRes, new ArrayList<>(Arrays.asList(models)));
  }

  /**
   * @param layoutRes The layout to use with these models.
   * @param models    The models that will be used to bind the views in the given layout.
   */
  private EpoxyModelGroup(@LayoutRes int layoutRes, List<EpoxyModel<?>> models) {
    if (models.isEmpty()) {
      throw new IllegalArgumentException("Models cannot be empty");
    }

    this.models = models;
    layout(layoutRes);
    id(models.get(0).id());

    boolean saveState = false;
    for (EpoxyModel<?> model : models) {
      if (model.shouldSaveViewState()) {
        saveState = true;
        break;
      }
    }
    // By default we save view state if any of the models need to save state.
    shouldSaveViewStateDefault = saveState;
  }

  /**

View on GitHub (pinned to e45bd3a61f)