JakeWharton/butterknife · error · IllegalStateException
@BindViews must be a List or array. (
Error message
@BindViews must be a List or array. (
What it means
@BindViews only supports two field shapes: an array or exactly java.util.List. parseBindViews checks field.getType(); anything else — an ArrayList subtype, a Collection, a Set, a single View, a CharSequence — falls into the final else and throws this IllegalStateException at bind time.
Source
Thrown at butterknife-reflect/src/main/java/butterknife/ButterKnife.java:291
Class<?> viewClass;
boolean isArray = fieldClass.isArray();
if (isArray) {
viewClass = fieldClass.getComponentType();
} else if (fieldClass == List.class) {
Type fieldType = field.getGenericType();
if (fieldType instanceof ParameterizedType) {
Type viewType = ((ParameterizedType) fieldType).getActualTypeArguments()[0];
// TODO real rawType impl!!!!
viewClass = (Class<?>) viewType;
} else {
throw new IllegalStateException("@BindViews List must have a generic component. ("
+ field.getDeclaringClass().getName()
+ '.'
+ field.getName()
+ ')');
}
} else {
throw new IllegalStateException("@BindViews must be a List or array. ("
+ field.getDeclaringClass().getName()
+ '.'
+ field.getName()
+ ')');
}
if (!View.class.isAssignableFrom(viewClass) && !viewClass.isInterface()) {
throw new IllegalStateException(
"@BindViews List or array type must extend from View or be an interface. ("
+ field.getDeclaringClass().getName()
+ '.'
+ field.getName()
+ ')');
}
int[] ids = bindViews.value();
if (ids.length == 0) {
throw new IllegalStateException("@BindViews must specify at least one ID. ("
+ field.getDeclaringClass().getName()View on GitHub (pinned to fcdebedf32)
Solutions
- Declare the field as `List<TextView>` (or `TextView[]`) instead of ArrayList/Set/Collection
- Use @BindView on a single-view field instead of @BindViews
Example fix
// before
@BindViews({R.id.a, R.id.b})
ArrayList<TextView> labels;
// after
@BindViews({R.id.a, R.id.b})
List<TextView> labels; Defensive patterns
Strategy: type-guard
Validate before calling
Class<?> t = field.getType();
if (!t.isArray() && t != List.class) {
throw new IllegalStateException("@BindViews needs List or array: " + field);
} Type guard
static boolean isBindViewsContainer(Field f) {
Class<?> t = f.getType();
return t.isArray() || t == List.class;
} Prevention
- Declare @BindViews fields as the List interface or an array, never ArrayList/Set/Collection
- Use @BindView for a single view
When it happens
Trigger: `@BindViews({...}) ArrayList<TextView> views;` (ArrayList is a subtype, not List itself); `Set<TextView>`; `Collection<TextView>`; annotating a single View field with @BindViews.
Common situations: Developers declaring concrete collection implementations (ArrayList/LinkedList) instead of the List interface; mixing up @BindView (single) and @BindViews (many).
Related errors
- @BindView fields must extend from View or be an interface. (
- @BindViews List or array type must extend from View or be an
- @BindAnim field type must be 'Animation'. (
- @BindArray field type must be one of: String[], int[], CharS
- @BindBitmap field type must be 'Bitmap'. (
AI-assisted analysis of JakeWharton/butterknife@fcdebedf32 (2026-08-14).
Data as JSON: /api/errors/228bf24110d64cb3.
Report an issue: GitHub.