{"record":{"id":"07fb0262af24a3f5","repo":"airbnb/epoxy","slug":"no-view-exists-at-position-position","errorCode":null,"errorMessage":"No view exists at position $position","messagePattern":"No view exists at position \\$position","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"epoxy-adapter/src/main/java/com/airbnb/epoxy/ModelGroupHolder.kt","lineNumber":238,"sourceCode":"        if (inflatedId != View.NO_ID) {\n            view.id = inflatedId\n        }\n\n        if (useStubLayoutParams) {\n            viewGroup.addView(view, position, viewStub.layoutParams)\n        } else {\n            viewGroup.addView(view, position)\n        }\n    }\n\n    fun resetStub() {\n        removeCurrentView()\n        viewGroup.addView(viewStub, position)\n    }\n\n    private fun removeCurrentView() {\n        val view = viewGroup.getChildAt(position)\n            ?: throw IllegalStateException(\"No view exists at position $position\")\n        viewGroup.removeView(view)\n    }\n}\n\n/**\n * Local pool to the [ModelGroupHolder]\n */\nprivate class LocalGroupRecycledViewPool : RecyclerView.RecycledViewPool()\n\n/**\n * A viewholder's viewtype can only be set internally in an adapter when the viewholder\n * is created. To work around that we do the creation in an adapter.\n */\nprivate class HelperAdapter : RecyclerView.Adapter<EpoxyViewHolder>() {\n\n    private var model: EpoxyModel<*>? = null\n    private var modelGroupParent: ViewParent? = null\n","sourceCodeStart":220,"sourceCodeEnd":256,"githubUrl":"https://github.com/airbnb/epoxy/blob/e45bd3a61fe3a1f130e184f5b8dcf172ab99025a/epoxy-adapter/src/main/java/com/airbnb/epoxy/ModelGroupHolder.kt#L220-L256","documentation":"When resetting a ViewStub, removeCurrentView first removes whatever inflated view currently occupies the stub's position in the parent ViewGroup. If getChildAt(position) returns null, the position holds no view, so resetStub cannot proceed and throws this IllegalStateException rather than silently corrupting view ordering.","triggerScenarios":"Calling resetStub on a stub slot after the inflated view was already removed or never inflated; position drift caused by views being added/removed from the parent ViewGroup out of band.","commonSituations":"Rebinding a model group where a stub was reset earlier and its view recycled away; external code removing child views from the group's container; calling resetStub before the stub was inflated.","solutions":["Only call resetStub for stub positions that currently hold an inflated view; check viewGroup.childCount first.","Ensure the ViewGroup contents are managed exclusively by ModelGroupHolder — no external add/removeView calls.","Rebind the group instead of resetting an already-cleared stub slot.","If the view was removed elsewhere, re-add it via the normal bind path rather than resetStub."],"exampleFix":"// before\nholder.resetStub(position) // throws if no view at position\n\n// after\nif (position < viewGroup.childCount && viewGroup.getChildAt(position) != null) {\n  holder.resetStub(position)\n}","handlingStrategy":"validation","validationCode":"fun canResetStub(parent: ViewGroup, position: Int) =\n  position in 0 until parent.childCount && parent.getChildAt(position) != null","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Do not add/remove children of the group's ViewGroup outside ModelGroupHolder.","Reset stubs only between bind cycles, not after views were recycled away.","Prefer a full rebind over targeted resetStub when state is uncertain."],"tags":["android","epoxy","viewstub","view-position","illegal-state"],"backgroundTag":"index-out-of-bounds","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"}