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

  1. Only access holder state inside bind/unbind or RecyclerView callbacks where the holder is guaranteed bound
  2. Drop long-lived references to EpoxyViewHolder; store the model or id instead
  3. Guard custom code with holder.isBound()/check the model exists before use; re-fetch the holder via RecyclerView.findViewHolderForAdapterPosition
  4. 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

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


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)