{"record":{"id":"cca59f9cdf519af4","repo":"airbnb/epoxy","slug":"models-must-not-be-empty","errorCode":null,"errorMessage":"Models must not be empty","messagePattern":"Models must not be empty","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"epoxy-adapter/src/main/java/com/airbnb/epoxy/DiffPayload.java","lineNumber":22,"sourceCode":"import java.util.List;\n\nimport androidx.annotation.Nullable;\nimport androidx.annotation.VisibleForTesting;\nimport androidx.collection.LongSparseArray;\n\n/**\n * A helper class for tracking changed models found by the {@link com.airbnb.epoxy.DiffHelper} to\n * be included as a payload in the\n * {@link androidx.recyclerview.widget.RecyclerView.Adapter#notifyItemChanged(int, Object)}\n * call.\n */\npublic class DiffPayload {\n  private final EpoxyModel<?> singleModel;\n  private final LongSparseArray<EpoxyModel<?>> modelsById;\n\n  DiffPayload(List<? extends EpoxyModel<?>> models) {\n    if (models.isEmpty()) {\n      throw new IllegalStateException(\"Models must not be empty\");\n    }\n\n    int modelCount = models.size();\n\n    if (modelCount == 1) {\n      // Optimize for the common case of only one model changed.\n      singleModel = models.get(0);\n      modelsById = null;\n    } else {\n      singleModel = null;\n      modelsById = new LongSparseArray<>(modelCount);\n      for (EpoxyModel<?> model : models) {\n        modelsById.put(model.id(), model);\n      }\n    }\n  }\n\n  public DiffPayload(EpoxyModel<?> changedItem) {","sourceCodeStart":4,"sourceCodeEnd":40,"githubUrl":"https://github.com/airbnb/epoxy/blob/e45bd3a61fe3a1f130e184f5b8dcf172ab99025a/epoxy-adapter/src/main/java/com/airbnb/epoxy/DiffPayload.java#L4-L40","documentation":"DiffPayload's package-private constructor requires a non-empty list of changed models; an empty list throws IllegalStateException. Payloads describe the old versions of models for a change notification, so an empty list means nothing changed and no payload should be created.","triggerScenarios":"Constructing DiffPayload with an empty List<EpoxyModel<?>> — only reachable via onItemRangeChanged in DiffHelper passing a payload list with no models, or via direct construction in the same package/tests.","commonSituations":"Modified/forked DiffHelper code that adds empty payload lists for change notifications; test code building DiffPayload directly; library-internal edge cases on stock code are not expected to hit this.","solutions":["Skip creating a payload when the changed-models list is empty (emit plain notifyItemRangeChanged instead)","Use stock epoxy versions rather than forks that may pass empty lists","In tests, never build DiffPayload with an empty list; assert models before constructing"],"exampleFix":"// before\nnew DiffPayload(Collections.emptyList()); // throws\n\n// after\nif (!models.isEmpty()) {\n  new DiffPayload(models);\n}","handlingStrategy":"validation","validationCode":"// only create a payload when there is at least one model\nif (models.isEmpty()) return;\nnew DiffPayload(models);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Skip payload creation for empty change sets","Prefer stock DiffHelper, which never passes empty lists","In tests, guard DiffPayload construction with an isEmpty check"],"tags":["android","epoxy","diffing","payload"],"backgroundTag":"empty-required-field","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"}