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

  1. Declare the field as `List<TextView>` (or `TextView[]`) instead of ArrayList/Set/Collection
  2. 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

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


AI-assisted analysis of JakeWharton/butterknife@fcdebedf32 (2026-08-14). Data as JSON: /api/errors/228bf24110d64cb3. Report an issue: GitHub.