{"record":{"id":"25d8857e9315dd71","repo":"airbnb/epoxy","slug":"insufficient-view-stubs-for-epoxymodelgroup-modelcount","errorCode":null,"errorMessage":"Insufficient view stubs for EpoxyModelGroup. $modelCount models were provided but only ${stubs.size} view stubs exist.","messagePattern":"Insufficient view stubs for EpoxyModelGroup\\. \\$modelCount models were provided but only (.+?) view stubs exist\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"epoxy-adapter/src/main/java/com/airbnb/epoxy/ModelGroupHolder.kt","lineNumber":111,"sourceCode":"        if (previouslyBoundGroup === group) {\n            return\n        } else if (previouslyBoundGroup != null) {\n            // A different group is being bound; this can happen when an onscreen model is changed.\n            // The models or their layouts could have changed, so views may need to be updated\n\n            if (previouslyBoundGroup.models.size > group.models.size) {\n                for (i in previouslyBoundGroup.models.size - 1 downTo group.models.size) {\n                    removeAndRecycleView(i)\n                }\n            }\n        }\n\n        this.boundGroup = group\n        val models = group.models\n        val modelCount = models.size\n\n        if (usingStubs() && stubs.size < modelCount) {\n            throw IllegalStateException(\n                \"Insufficient view stubs for EpoxyModelGroup. $modelCount models were provided but only ${stubs.size} view stubs exist.\"\n            )\n        }\n        viewHolders.ensureCapacity(modelCount)\n\n        for (i in 0 until modelCount) {\n            val model = models[i]\n            val previouslyBoundModel = previouslyBoundGroup?.models?.getOrNull(i)\n            val stubData = stubs.getOrNull(i)\n            val parent = stubData?.viewGroup ?: childContainer\n\n            if (previouslyBoundModel != null) {\n                if (areSameViewType(previouslyBoundModel, model)) {\n                    continue\n                }\n\n                removeAndRecycleView(i)\n            }","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/airbnb/epoxy/blob/e45bd3a61fe3a1f130e184f5b8dcf172ab99025a/epoxy-adapter/src/main/java/com/airbnb/epoxy/ModelGroupHolder.kt#L93-L129","documentation":"An EpoxyModelGroup needs at least one ViewStub per model so each model can be bound into its own stub. When the holder is in stub mode (usingStubs()) and the number of stubs in the layout is less than the number of models in the group, bindGroupIfNeeded throws this IllegalStateException because some models would have no view to bind to.","triggerScenarios":"Creating an EpoxyModelGroup with N models while its layout contains fewer than N ViewStub children (e.g. 3 models, 2 stubs).","commonSituations":"Adding models to a group without updating the group's layout to add matching stubs; reusing one group layout for differently sized groups; dynamic model-count changes at runtime not mirrored in the layout.","solutions":["Add ViewStub entries to the group layout so stub count >= model count.","Reduce the number of models in the EpoxyModelGroup to match the available stubs.","Build the layout dynamically from the model list so stub count always tracks models.size().","Check that you are not accidentally binding the same group layout to a larger model list after a refactor."],"exampleFix":"// before\nEpoxyModelGroup(models = listOf(modelA, modelB, modelC), layoutRes = R.layout.group_two_stubs)\n\n// after: add a third ViewStub to group layout, or\nEpoxyModelGroup(models = listOf(modelA, modelB), layoutRes = R.layout.group_two_stubs)","handlingStrategy":"validation","validationCode":"fun validateGroupLayout(modelCount: Int, stubLayoutRes: Int, context: Context) {\n  val stubs = countStubs(LayoutInflater.from(context).inflate(stubLayoutRes, null))\n  require(stubs >= modelCount) { \"Need $modelCount stubs, layout has $stubs\" }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Generate the group layout from the model list or keep a 1:1 stub-per-model comment in the layout file.","Add a unit test that binds every group layout with its maximum model count.","Re-check stub counts whenever you change the size of a group's model list."],"tags":["android","epoxy","viewstub","modelgroup","count-mismatch"],"backgroundTag":"value-out-of-range","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"}