airbnb/epoxy · error · IllegalStateException
This holder is not currently bound.
Error message
This holder is not currently bound.
What it means
EpoxyViewHolder caches its bound EpoxyModel; assertBound throws IllegalStateException whenever any accessor is used after the holder has been unbound (epoxyModel == null). It protects against using stale holder state outside the bind lifecycle.
Solutions
- Only access holder state inside bind/unbind or RecyclerView callbacks where the holder is guaranteed bound
- Drop long-lived references to EpoxyViewHolder; store the model or id instead
- Guard custom code with holder.isBound()/check the model exists before use; re-fetch the holder via RecyclerView.findViewHolderForAdapterPosition
- Null-check getModel() results where Epoxy already returns try/catch semantics (see onChildDraw pattern)
Example fix
// before
EpoxyViewHolder vh = myRef; vh.getModel(); // may be unbound
// after
if (myRef != null && recyclerView.findViewHolderForAdapterPosition(pos) == myRef) {
EpoxyModel<?> m = myRef.getModel();
} Defensive patterns
Strategy: type-guard
Validate before calling
EpoxyViewHolder vh = (EpoxyViewHolder) recyclerView.findViewHolderForAdapterPosition(pos); if (vh == null) return; // not bound / off-screen
Type guard
boolean isBound(EpoxyViewHolder vh) { try { vh.getModel(); return true; } catch (IllegalStateException e) { return false; } } Try / catch
try { EpoxyModel<?> m = vh.getModel(); use(m); } catch (IllegalStateException e) { Log.w(TAG, "holder not bound", e); } Prevention
- Never cache EpoxyViewHolder references across frames
- Access holder state only inside bind/unbind or RecyclerView callbacks
- Re-resolve holders via RecyclerView lookups instead of stored refs
When it happens
Trigger: Calling getModel(), getHolder(), getPayloads(), unbind(), or visibility state callbacks on an EpoxyViewHolder that is not currently bound (already unbound, or before binding).
Common situations: Holding a reference to a ViewHolder across RecyclerView recycling; calling visibility APIs (onVisibilityStateChanged/Changed) after unbind; custom touch/swipe logic reading getModel() from a recycled holder.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Can only call this when inside the `buildModels` method
- Cannot call this from inside `buildModels`
- You cannot call `buildModels` directly. Call `setModels`…
- You cannot call `requestModelBuild` directly. Call…
- You cannot call `buildModels` directly. Call `setData`…
AI-assisted analysis of airbnb/epoxy@e45bd3a61f (2026-09-13).
Data as JSON: /api/errors/6d7aae535f53ce12.
Report an issue: GitHub.
Appendix: source
Thrown at epoxy-adapter/src/main/java/com/airbnb/epoxy/EpoxyViewHolder.java:135
public List<Object> getPayloads() {
assertBound();
return payloads;
}
public EpoxyModel<?> getModel() {
assertBound();
return epoxyModel;
}
public EpoxyHolder getHolder() {
assertBound();
return epoxyHolder;
}
private void assertBound() {
if (epoxyModel == null) {
throw new IllegalStateException("This holder is not currently bound.");
}
}
@Override
public String toString() {
return "EpoxyViewHolder{"
+ "epoxyModel=" + epoxyModel
+ ", view=" + itemView
+ ", super=" + super.toString()
+ '}';
}
}
View on GitHub (pinned to e45bd3a61f)