JakeWharton/butterknife · error · IllegalStateException

@BindInt field type must be 'int'. (

Error message

@BindInt field type must be 'int'. (

What it means

Thrown by the reflection-based ButterKnife runtime when a field annotated with @BindInt is not declared as primitive int. The binder resolves the integer resource with Resources.getInteger and only assigns to int.class; long, Integer, and float fields are rejected.

Source

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

    return Unbinder.EMPTY;
  }

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

    int id = bindInt.value();
    Resources resources = source.getContext().getResources();

    Class<?> fieldType = field.getType();
    Object value;
    if (fieldType == int.class) {
      value = resources.getInteger(id);
    } else {
      throw new IllegalStateException("@BindInt field type must be 'int'. ("
          + field.getDeclaringClass().getName()
          + '.'
          + field.getName()
          + ')');
    }
    trySet(field, target, value);

    return Unbinder.EMPTY;
  }

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

    int id = bindString.value();

View on GitHub (pinned to fcdebedf32)

Solutions

  1. Change the field to primitive `int`.
  2. If a long/Integer is required downstream, keep the int field and convert after bind.
  3. For non-integer resources use @BindFloat/@BindDimen; for compile-time safety switch to butterknife-compiler.

Example fix

// before
@BindInt(R.int.anim_duration_ms) Long durationMs;

// after
@BindInt(R.int.anim_duration_ms) int durationMs;
Defensive patterns

Strategy: type-guard

Validate before calling

for (Field f : targetClass.getDeclaredFields()) {
  if (f.isAnnotationPresent(BindInt.class) && f.getType() != int.class) {
    throw new IllegalStateException(f + " must be int");
  }
}

Type guard

static boolean isValidBindIntField(Field f) {
  return !f.isAnnotationPresent(BindInt.class) || f.getType() == int.class;
}

Prevention

When it happens

Trigger: ButterKnife.bind(...) via butterknife-reflect on a class with `@BindInt(R.int.max_count) Integer maxCount;`, `@BindInt(R.int.max_count) long maxCount;`, or `@BindInt(R.int.max_count) float maxCount;`.

Common situations: Boxing the field for nullability or API models, widening to long for counters, or annotating a dimen/float resource with @BindInt by mistake. Compile-time binder (butterknife-compiler) rejects this during build; only the reflect artifact throws at bind time.

Related errors


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