JakeWharton/butterknife · error · IllegalStateException

Multiple listener methods specified on @%s.

Error message

Multiple listener methods specified on @%s.

What it means

@ListenerClass supports two mutually exclusive shapes: exactly one method() entry, or a callbacks() enum (including the default NONE sentinel). If a @ListenerClass declares more than one @ListenerMethod in its method() attribute, the processor cannot decide which listener method to bind and throws this IllegalStateException. This is a compile-time contract violation in the annotation definition.

Source

Thrown at butterknife-compiler/src/main/java/butterknife/compiler/ButterKnifeProcessor.java:1105

        if (ids.length == 1) {
          if (!required) {
            error(element, "ID-free binding must not be annotated with @Optional. (%s.%s)",
                enclosingElement.getQualifiedName(), element.getSimpleName());
            hasError = true;
          }
        } else {
          error(element, "@%s annotation contains invalid ID %d. (%s.%s)",
              annotationClass.getSimpleName(), id, enclosingElement.getQualifiedName(),
              element.getSimpleName());
          hasError = true;
        }
      }
    }

    ListenerMethod method;
    ListenerMethod[] methods = listener.method();
    if (methods.length > 1) {
      throw new IllegalStateException(String.format("Multiple listener methods specified on @%s.",
          annotationClass.getSimpleName()));
    } else if (methods.length == 1) {
      if (listener.callbacks() != ListenerClass.NONE.class) {
        throw new IllegalStateException(
            String.format("Both method() and callback() defined on @%s.",
                annotationClass.getSimpleName()));
      }
      method = methods[0];
    } else {
      Method annotationCallback = annotationClass.getDeclaredMethod("callback");
      Enum<?> callback = (Enum<?>) annotationCallback.invoke(annotation);
      Field callbackField = callback.getDeclaringClass().getField(callback.name());
      method = callbackField.getAnnotation(ListenerMethod.class);
      if (method == null) {
        throw new IllegalStateException(
            String.format("No @%s defined on @%s's %s.%s.", ListenerMethod.class.getSimpleName(),
                annotationClass.getSimpleName(), callback.getDeclaringClass().getSimpleName(),
                callback.name()));

View on GitHub (pinned to fcdebedf32)

Solutions

  1. Keep only one @ListenerMethod in method() and remove the extras
  2. If multiple callbacks are needed, remove method() and provide a callbacks() enum whose constants each carry @ListenerMethod

Example fix

// before
@ListenerClass(method = {
    @ListenerMethod(name = "onClick", parameters = {View.class}),
    @ListenerMethod(name = "onLongClick", parameters = {View.class})})
public @interface OnClickOrLong { ... }

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

Strategy: validation

Validate before calling

ListenerClass lc = OnCustomEvent.class.getAnnotation(ListenerClass.class);
if (lc.method().length > 1) {
  throw new IllegalStateException("Use callbacks(), not multiple method() entries");
}

Prevention

When it happens

Trigger: Declaring @ListenerClass(method = {@ListenerMethod(...), @ListenerMethod(...)}) with two or more entries on a custom listener annotation.

Common situations: Attempting to make one custom annotation bind several callbacks by listing multiple method entries; misunderstanding that multi-callback listeners use the callbacks enum instead.

Related errors


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