JakeWharton/butterknife · error · IllegalStateException

@BindAnim field type must be 'Animation'. (

Error message

@BindAnim field type must be 'Animation'. (

What it means

@BindAnim loads an android.view.animation.Animation via AnimationUtils.loadAnimation and therefore only accepts a field whose exact type is Animation. parseBindAnim checks field.getType() == Animation.class; any other type — including a subclass like ScaleAnimation — throws this IllegalStateException at bind time.

Source

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

    return new FieldUnbinder(target, field);
  }

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

    int id = bindAnim.value();
    Context context = source.getContext();

    Object value;
    Class<?> fieldType = field.getType();
    if (fieldType == Animation.class) {
      value = AnimationUtils.loadAnimation(context, id);
    } else {
      throw new IllegalStateException("@BindAnim field type must be 'Animation'. ("
          + field.getDeclaringClass().getName()
          + '.'
          + field.getName()
          + ')');
    }
    trySet(field, target, value);

    return Unbinder.EMPTY;
  }

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

    int id = bindArray.value();

View on GitHub (pinned to fcdebedf32)

Solutions

  1. Declare the field exactly as `Animation`: `@BindAnim(R.anim.fade) Animation fade;`
  2. For property animators, load them manually with AnimatorInflater/AnimatorInflaterCompat instead of @BindAnim

Example fix

// before
@BindAnim(R.anim.fade_in)
ScaleAnimation fadeIn;

// after
@BindAnim(R.anim.fade_in)
Animation fadeIn;
Defensive patterns

Strategy: type-guard

Validate before calling

if (field.getType() != Animation.class) {
  throw new IllegalStateException("@BindAnim field must be Animation: " + field);
}

Type guard

static boolean isAnimationField(Field f) {
  return f.getType() == android.view.animation.Animation.class;
}

Prevention

When it happens

Trigger: `@BindAnim(R.anim.fade) ScaleAnimation fade;` (subclass instead of Animation); typing the field as Object or a KTX animator type; intending an Animator/AnimatorSet (which is not supported by @BindAnim).

Common situations: Confusing view animations (Animation) with property animators (Animator) from android.animation; refactoring a field to the concrete animation class returned by a loader.

Related errors


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