JakeWharton/butterknife · error · IllegalStateException

@%s's %s.%s missing @%s annotation.

Error message

@%s's %s.%s missing @%s annotation.

What it means

Thrown during annotation processing while building the binding set for a listener annotation whose @ListenerClass declares a callbacks() enum (i.e. method() does not have exactly one entry). For every enum constant in the callbacks enum, the processor reflects on the corresponding Field and expects an @ListenerMethod annotation; when one constant lacks it, this IllegalStateException is thrown. It is a defect in the definition of the custom listener annotation (or of ButterKnife's own callback enums), not in user binding code.

Source

Thrown at butterknife-compiler/src/main/java/butterknife/compiler/BindingSet.java:553

    if (needsNullChecked) {
      result.endControlFlow();
    }
  }

  private static List<ListenerMethod> getListenerMethods(ListenerClass listener) {
    if (listener.method().length == 1) {
      return Arrays.asList(listener.method());
    }

    try {
      List<ListenerMethod> methods = new ArrayList<>();
      Class<? extends Enum<?>> callbacks = listener.callbacks();
      for (Enum<?> callbackMethod : callbacks.getEnumConstants()) {
        Field callbackField = callbacks.getField(callbackMethod.name());
        ListenerMethod method = callbackField.getAnnotation(ListenerMethod.class);
        if (method == null) {
          throw new IllegalStateException(String.format("@%s's %s.%s missing @%s annotation.",
              callbacks.getEnclosingClass().getSimpleName(), callbacks.getSimpleName(),
              callbackMethod.name(), ListenerMethod.class.getSimpleName()));
        }
        methods.add(method);
      }
      return methods;
    } catch (NoSuchFieldException e) {
      throw new AssertionError(e);
    }
  }

  static String asHumanDescription(Collection<? extends MemberViewBinding> bindings) {
    Iterator<? extends MemberViewBinding> iterator = bindings.iterator();
    switch (bindings.size()) {
      case 1:
        return iterator.next().getDescription();
      case 2:
        return iterator.next().getDescription() + " and " + iterator.next().getDescription();

View on GitHub (pinned to fcdebedf32)

Solutions

  1. Open the callbacks enum referenced by @ListenerClass(callbacks = ...) and add an @ListenerMethod(name = ..., parameters = ...) annotation to every constant reported in the message
  2. If the constant should not be bound, remove it from the enum or use a enum whose constants all carry @ListenerMethod
  3. If you are not intentionally using callbacks, set @ListenerClass(method = @ListenerMethod(...)) with exactly one method instead of a callbacks enum

Example fix

// before
public enum Callback {
  CLICK,
  LONG_CLICK // missing @ListenerMethod
}

// after
public enum Callback {
  @ListenerMethod(name = "onClick", parameters = {View.class})
  CLICK,
  @ListenerMethod(name = "onLongClick", parameters = {View.class})
  LONG_CLICK
}
Defensive patterns

Strategy: validation

Validate before calling

// At library/test startup, verify every callbacks enum is fully annotated
void verifyListenerCallbacks(Class<? extends Enum<?>> callbacks) {
  for (Enum<?> constant : callbacks.getEnumConstants()) {
    Field f = callbacks.getField(constant.name());
    if (f.getAnnotation(ListenerMethod.class) == null) {
      throw new IllegalStateException(callbacks + "." + constant.name() + " missing @ListenerMethod");
    }
  }
}

Prevention

When it happens

Trigger: Defining @ListenerClass(callbacks = MyCallback.class) where MyCallback is an enum, and at least one enum constant (e.g. MY_CALLBACK) is not annotated with @ListenerMethod. Also triggered by adding a new constant to an existing callbacks enum (such as a copied OnItemSelected.Callback) without giving it an @ListenerMethod annotation; the processor hits it when generating the binder class for any @OnX method using that listener.

Common situations: Writing a custom listener annotation modeled after ButterKnife's @OnItemSelected/@OnTextChanged; upgrading ButterKnife versions where a callbacks enum gained new constants; hand-editing a fork of the library and forgetting one enum constant.

Related errors


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