JakeWharton/butterknife · error · IllegalStateException

View '{}' with ID {} for {} was of the wrong type. See cause

Error message

View '{}' with ID {} for {} was of the wrong type. See cause for more info.

What it means

Thrown by Utils.castView when the view found for a bound ID exists but cannot be cast to the annotated field's type. The original ClassCastException is preserved as the cause; the message identifies the resource entry name, ID, and the binding target ('who') so you can compare XML vs Java types.

Source

Thrown at butterknife-runtime/src/main/java/butterknife/internal/Utils.java:105

        + id
        + " for "
        + who
        + " was not found. If this view is optional add '@Nullable' (fields) or '@Optional'"
        + " (methods) annotation.");
  }

  public static <T> T findRequiredViewAsType(View source, @IdRes int id, String who,
      Class<T> cls) {
    View view = findRequiredView(source, id, who);
    return castView(view, id, who, cls);
  }

  public static <T> T castView(View view, @IdRes int id, String who, Class<T> cls) {
    try {
      return cls.cast(view);
    } catch (ClassCastException e) {
      String name = getResourceEntryName(view, id);
      throw new IllegalStateException("View '"
          + name
          + "' with ID "
          + id
          + " for "
          + who
          + " was of the wrong type. See cause for more info.", e);
    }
  }

  public static <T> T castParam(Object value, String from, int fromPos, String to, int toPos,
      Class<T> cls) {
    try {
      return cls.cast(value);
    } catch (ClassCastException e) {
      throw new IllegalStateException("Parameter #"
          + (fromPos + 1)
          + " of method '"
          + from

View on GitHub (pinned to fcdebedf32)

Solutions

  1. Align the types: change the field type to the XML widget's class (or a supertype of it).
  2. Check for ID collisions across includes/merge and rename the duplicate ID.
  3. If polymorphism is expected (same ID different types across variants), bind to the common supertype (e.g. View or TextView).

Example fix

<!-- before -->
<ImageView android:id="@+id/media" ... />
@BindView(R.id.media) TextView media; // wrong type

<!-- after -->
<ImageView android:id="@+id/media" ... />
@BindView(R.id.media) ImageView media;
Defensive patterns

Strategy: type-guard

Validate before calling

View v = sourceView.findViewById(R.id.media);
if (v != null && !TextView.class.isAssignableFrom(v.getClass())) {
  // XML type differs from field type — fix layout or field before bind
}

Type guard

static boolean viewMatchesFieldType(View v, Class<?> fieldType) {
  return v == null || fieldType.isAssignableFrom(v.getClass());
}

Prevention

When it happens

Trigger: `@BindView(R.id.title) TextView title;` where XML declares `<androidx.appcompat.widget.AppCompatEditText android:id="@id/title" ...>` — any mismatch between the XML widget class and the annotated field type, e.g. EditText vs TextView is fine (upcast) but TextView vs ImageView, or a custom view replaced by its subclass, throws.

Common situations: Renaming/replacing a widget in XML during a redesign while the Java field keeps the old type; merging layouts where an ID collides across include/merge tags; support-library migrations changing actual inflated classes; a wrong <include> bringing another layout's view with the same ID first in the hierarchy.

Related errors


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