airbnb/epoxy · error · IllegalEpoxyUsage
You must set an id on a model before adding it. Use the…
Error message
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.
What it means
EpoxyController.addInternal validates every model added during buildModels. A model whose id is still the default (unset) cannot participate in diffing/recycling, so IllegalEpoxyUsage is thrown, pointing you to set an id or use @AutoModel for generated ids.
Solutions
- Call .id(...) with a stable unique value on every model before addTo
- Use the @AutoModel annotation on a field and add via that field so an id is generated
- Verify the Epoxy annotation processor is configured (kapt/ksp) so @AutoModel works
- If id legitimately depends on content, derive it from the bound data (e.g. item.getId())
Example fix
// before
new HeaderModel_("Hello").addTo(this); // crash
// after
new HeaderModel_("Hello").id("header").addTo(this); Defensive patterns
Strategy: validation
Validate before calling
if (model.hasDefaultId()) { model.id(computeId()); } model.addTo(controller); Try / catch
try { model.addTo(controller); } catch (IllegalEpoxyUsage e) { model.id(uniqueId).addTo(controller); } Prevention
- Always chain .id(...) on every generated model before addTo
- Use @AutoModel for singleton models and verify kapt/ksp annotation processing is set up
- Derive ids from stable data keys so diffs behave correctly
When it happens
Trigger: Calling addTo/addInternal with a model on which .id(...) was never called; forgetting id on a dynamically created model (new FooModel_()); relying on @AutoModel without applying the annotation processor.
Common situations: Constructing a generated model class and adding it without chaining .id(); a refactor removing the .id() call; the Epoxy annotation processor not running so @AutoModel fields are not generated/assigned.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- Controller cannot be null
- This model was already added to the controller at position
- Epoxy attribute fields on a model cannot be changed once…
- Models cannot be empty
- Must have stable ids when saving view holder state
AI-assisted analysis of airbnb/epoxy@e45bd3a61f (2026-09-13).
Data as JSON: /api/errors/776fa221ed2b678e.
Report an issue: GitHub.
Appendix: source
Thrown at epoxy-adapter/src/main/java/com/airbnb/epoxy/EpoxyController.java:502
* EpoxyController#buildModels()}.
*/
protected void add(@NonNull List<? extends EpoxyModel<?>> modelsToAdd) {
modelsBeingBuilt.ensureCapacity(modelsBeingBuilt.size() + modelsToAdd.size());
for (EpoxyModel<?> model : modelsToAdd) {
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);
}
/**View on GitHub (pinned to e45bd3a61f)