{"record":{"id":"de0dcfdc2284d9ab","repo":"JakeWharton/butterknife","slug":"bindanim-field-type-must-be-animation","errorCode":null,"errorMessage":"@BindAnim field type must be 'Animation'. (","messagePattern":"@BindAnim field type must be 'Animation'\\. \\(","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"butterknife-reflect/src/main/java/butterknife/ButterKnife.java","lineNumber":351,"sourceCode":"    return new FieldUnbinder(target, field);\n  }\n\n  private static @Nullable Unbinder parseBindAnim(Object target, Field field, View source) {\n    BindAnim bindAnim = field.getAnnotation(BindAnim.class);\n    if (bindAnim == null) {\n      return null;\n    }\n    validateMember(field);\n\n    int id = bindAnim.value();\n    Context context = source.getContext();\n\n    Object value;\n    Class<?> fieldType = field.getType();\n    if (fieldType == Animation.class) {\n      value = AnimationUtils.loadAnimation(context, id);\n    } else {\n      throw new IllegalStateException(\"@BindAnim field type must be 'Animation'. (\"\n          + field.getDeclaringClass().getName()\n          + '.'\n          + field.getName()\n          + ')');\n    }\n    trySet(field, target, value);\n\n    return Unbinder.EMPTY;\n  }\n\n  private static @Nullable Unbinder parseBindArray(Object target, Field field, View source) {\n    BindArray bindArray = field.getAnnotation(BindArray.class);\n    if (bindArray == null) {\n      return null;\n    }\n    validateMember(field);\n\n    int id = bindArray.value();","sourceCodeStart":333,"sourceCodeEnd":369,"githubUrl":"https://github.com/JakeWharton/butterknife/blob/fcdebedf3276096db2f51bf6372b849b5a9c75ed/butterknife-reflect/src/main/java/butterknife/ButterKnife.java#L333-L369","documentation":"@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.","triggerScenarios":"`@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).","commonSituations":"Confusing view animations (Animation) with property animators (Animator) from android.animation; refactoring a field to the concrete animation class returned by a loader.","solutions":["Declare the field exactly as `Animation`: `@BindAnim(R.anim.fade) Animation fade;`","For property animators, load them manually with AnimatorInflater/AnimatorInflaterCompat instead of @BindAnim"],"exampleFix":"// before\n@BindAnim(R.anim.fade_in)\nScaleAnimation fadeIn;\n\n// after\n@BindAnim(R.anim.fade_in)\nAnimation fadeIn;","handlingStrategy":"type-guard","validationCode":"if (field.getType() != Animation.class) {\n  throw new IllegalStateException(\"@BindAnim field must be Animation: \" + field);\n}","typeGuard":"static boolean isAnimationField(Field f) {\n  return f.getType() == android.view.animation.Animation.class;\n}","tryCatchPattern":null,"preventionTips":["Type @BindAnim fields exactly as android.view.animation.Animation","Use AnimatorInflater manually for property animators — @BindAnim does not support them"],"tags":["butterknife","runtime","reflection","type-mismatch","animation"],"backgroundTag":null,"analyzedSha":"fcdebedf3276096db2f51bf6372b849b5a9c75ed","analyzedAt":"2026-08-14T10:13:55.083Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}