JakeWharton/butterknife · error · IllegalStateException

@BindView fields must extend from View or be an interface. (

Error message

@BindView fields must extend from View or be an interface. (

What it means

parseBindView requires the annotated field's type to be a subclass of android.view.View or an interface (so the found view can be cast). Any other type — a String, a Drawable, a primitive, or a non-View class — throws this IllegalStateException during ButterKnife.bind in the reflect flavor. The compiler flavor enforces the same rule at build time; the reflect flavor enforces it at runtime.

Source

Thrown at butterknife-reflect/src/main/java/butterknife/ButterKnife.java:250

      if (debug) Log.d(TAG, "MISS: Reached framework class. Abandoning search.");
      return Unbinder.EMPTY;
    }

    if (debug) Log.d(TAG, "HIT: Reflectively found " + unbinders.size() + " bindings.");
    return new CompositeUnbinder(unbinders);
  }

  private static @Nullable Unbinder parseBindView(Object target, Field field, View source) {
    BindView bindView = field.getAnnotation(BindView.class);
    if (bindView == null) {
      return null;
    }
    validateMember(field);

    int id = bindView.value();
    Class<?> viewClass = field.getType();
    if (!View.class.isAssignableFrom(viewClass) && !viewClass.isInterface()) {
      throw new IllegalStateException(
          "@BindView fields must extend from View or be an interface. ("
              + field.getDeclaringClass().getName()
              + '.'
              + field.getName()
              + ')');
    }

    String who = "field '" + field.getName() + "'";
    Object view = Utils.findOptionalViewAsType(source, id, who, viewClass);
    trySet(field, target, view);

    return new FieldUnbinder(target, field);
  }

  private static @Nullable Unbinder parseBindViews(Object target, Field field, View source) {
    BindViews bindViews = field.getAnnotation(BindViews.class);
    if (bindViews == null) {
      return null;

View on GitHub (pinned to fcdebedf32)

Solutions

  1. Change the field type to a View subclass matching the XML tag (TextView, ImageView, custom View)
  2. If the ID refers to a resource rather than a view, use the matching annotation: @BindString, @BindDrawable, @BindColor, @BindDimen
  3. For collections of views use @BindViews with a List or array of a View type

Example fix

// before
@BindView(R.id.user_name)
String userName;

// after
@BindView(R.id.user_name)
TextView userNameView;
Defensive patterns

Strategy: type-guard

Validate before calling

Class<?> t = field.getType();
if (!View.class.isAssignableFrom(t) && !t.isInterface()) {
  throw new IllegalStateException("@BindView on non-View field: " + field);
}

Type guard

static boolean isBindableViewType(Class<?> c) {
  return View.class.isAssignableFrom(c) || c.isInterface();
}

Prevention

When it happens

Trigger: Annotating a field of a non-View type with @BindView, e.g. `@BindView(R.id.name) String name;` or `@BindView(R.id.icon) Drawable icon;`; using a custom class that wraps a view instead of extending View.

Common situations: Migrating from findViewById-style code where an id mapped to a resource rather than a view; intending @BindString/@BindDrawable but typing @BindView; generics or Parcelable fields annotated by mistake.

Related errors


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