airbnb/epoxy · error · IllegalStateException
A model was swiped that is not a valid target:
Error message
A model was swiped that is not a valid target:
What it means
When a swipe gesture completes, onSwiped validates that the swiped model is one the callback can handle via isTouchableModel before invoking onSwipeCompleted. A swipe on any other model type throws IllegalStateException including the model's class, since the callback has no typed swipe handler for it.
Solutions
- Update isTouchableModel to accept the model type you want swipable, and implement onSwipeCompleted for it
- Disable swiping for non-touchable models by overriding swipe-related enablement per view holder/position
- Consume swipes in getSwipeDirs (return 0 for models that are not touchable)
Example fix
// before
@Override public int getSwipeDirs(RecyclerView rv, RecyclerView.ViewHolder vh) { return ItemTouchHelper.LEFT; } // swipes everything
// after
@Override public int getSwipeDirs(RecyclerView rv, RecyclerView.ViewHolder vh) { return isTouchableModel(((EpoxyViewHolder) vh).getModel()) ? ItemTouchHelper.LEFT : 0; } Defensive patterns
Strategy: type-guard
Validate before calling
if (!touchCallback.isTouchableModel(viewHolder.getModel())) { return 0; } // no swipe dirs Type guard
if (viewHolder.getModel() instanceof MySwipableModel_) { /* safe to swipe */ } Try / catch
try { handleSwipe(model, direction); } catch (IllegalStateException e) { Log.e(TAG, "Swiped non-touchable model", e); } Prevention
- Return 0 swipe dirs for non-touchable models via getSwipeDirs
- Update isTouchableModel when adding new model types
- Test swipe gestures on every model type in the adapter
When it happens
Trigger: A swipe gesture lands on a model for which isTouchableModel(model) returns false, and onSwiped is invoked with that view holder.
Common situations: ItemTouchHelper swiping enabled for all view types while only some models are swipable; adding new model types to the adapter without updating the touch callback's isTouchableModel; swipe flags not filtered by position/type.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- A model was dragged that is not a valid target:
- Must have stable ids when saving view holder state
- State cannot be restored once views have been bound. It…
- Tried to restore instance state, but onSaveInstanceState…
- numItemsToPrefetch must be greater than 0
AI-assisted analysis of airbnb/epoxy@e45bd3a61f (2026-09-13).
Data as JSON: /api/errors/7cbf0bf487881e1d.
Report an issue: GitHub.
Appendix: source
Thrown at epoxy-adapter/src/main/java/com/airbnb/epoxy/EpoxyModelTouchCallback.java:102
//noinspection unchecked
onModelMoved(fromPosition, toPosition, (T) model, viewHolder.itemView);
return true;
}
@Override
public void onModelMoved(int fromPosition, int toPosition, T modelBeingMoved, View itemView) {
}
@Override
protected void onSwiped(EpoxyViewHolder viewHolder, int direction) {
EpoxyModel<?> model = viewHolder.getModel();
View view = viewHolder.itemView;
int position = viewHolder.getAdapterPosition();
if (!isTouchableModel(model)) {
throw new IllegalStateException(
"A model was swiped that is not a valid target: " + model.getClass());
}
//noinspection unchecked
onSwipeCompleted((T) model, view, position, direction);
}
@Override
public void onSwipeCompleted(T model, View itemView, int position, int direction) {
}
@Override
protected void onSelectedChanged(@Nullable EpoxyViewHolder viewHolder, int actionState) {
super.onSelectedChanged(viewHolder, actionState);
if (viewHolder != null) {
EpoxyModel<?> model = viewHolder.getModel();View on GitHub (pinned to e45bd3a61f)