{"record":{"id":"6d7aae535f53ce12","repo":"airbnb/epoxy","slug":"this-holder-is-not-currently-bound","errorCode":null,"errorMessage":"This holder is not currently bound.","messagePattern":"This holder is not currently bound\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"epoxy-adapter/src/main/java/com/airbnb/epoxy/EpoxyViewHolder.java","lineNumber":135,"sourceCode":"\n  public List<Object> getPayloads() {\n    assertBound();\n    return payloads;\n  }\n\n  public EpoxyModel<?> getModel() {\n    assertBound();\n    return epoxyModel;\n  }\n\n  public EpoxyHolder getHolder() {\n    assertBound();\n    return epoxyHolder;\n  }\n\n  private void assertBound() {\n    if (epoxyModel == null) {\n      throw new IllegalStateException(\"This holder is not currently bound.\");\n    }\n  }\n\n  @Override\n  public String toString() {\n    return \"EpoxyViewHolder{\"\n        + \"epoxyModel=\" + epoxyModel\n        + \", view=\" + itemView\n        + \", super=\" + super.toString()\n        + '}';\n  }\n}\n","sourceCodeStart":117,"sourceCodeEnd":148,"githubUrl":"https://github.com/airbnb/epoxy/blob/e45bd3a61fe3a1f130e184f5b8dcf172ab99025a/epoxy-adapter/src/main/java/com/airbnb/epoxy/EpoxyViewHolder.java#L117-L148","documentation":"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.","triggerScenarios":"Calling getModel(), getHolder(), getPayloads(), unbind(), or visibility state callbacks on an EpoxyViewHolder that is not currently bound (already unbound, or before binding).","commonSituations":"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.","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)"],"exampleFix":"// before\nEpoxyViewHolder vh = myRef; vh.getModel(); // may be unbound\n// after\nif (myRef != null && recyclerView.findViewHolderForAdapterPosition(pos) == myRef) {\n  EpoxyModel<?> m = myRef.getModel();\n}","handlingStrategy":"type-guard","validationCode":"EpoxyViewHolder vh = (EpoxyViewHolder) recyclerView.findViewHolderForAdapterPosition(pos);\nif (vh == null) return; // not bound / off-screen","typeGuard":"boolean isBound(EpoxyViewHolder vh) { try { vh.getModel(); return true; } catch (IllegalStateException e) { return false; } }","tryCatchPattern":"try { EpoxyModel<?> m = vh.getModel(); use(m); } catch (IllegalStateException e) { Log.w(TAG, \"holder not bound\", e); }","preventionTips":["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"],"tags":["android","epoxy","viewholder","lifecycle"],"backgroundTag":"invalid-state-transition","analyzedSha":"e45bd3a61fe3a1f130e184f5b8dcf172ab99025a","analyzedAt":"2026-09-13T03:24:16.052Z","contentChangedAt":"2026-09-13T03:24:16.052Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}