{"record":{"id":"0e7297347c901732","repo":"JakeWharton/butterknife","slug":"s-s-s-s-missing-s-annotation","errorCode":null,"errorMessage":"@%s's %s.%s missing @%s annotation.","messagePattern":"@(.+?)'s (.+?)\\.(.+?) missing @(.+?) annotation\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"butterknife-compiler/src/main/java/butterknife/compiler/BindingSet.java","lineNumber":553,"sourceCode":"\n    if (needsNullChecked) {\n      result.endControlFlow();\n    }\n  }\n\n  private static List<ListenerMethod> getListenerMethods(ListenerClass listener) {\n    if (listener.method().length == 1) {\n      return Arrays.asList(listener.method());\n    }\n\n    try {\n      List<ListenerMethod> methods = new ArrayList<>();\n      Class<? extends Enum<?>> callbacks = listener.callbacks();\n      for (Enum<?> callbackMethod : callbacks.getEnumConstants()) {\n        Field callbackField = callbacks.getField(callbackMethod.name());\n        ListenerMethod method = callbackField.getAnnotation(ListenerMethod.class);\n        if (method == null) {\n          throw new IllegalStateException(String.format(\"@%s's %s.%s missing @%s annotation.\",\n              callbacks.getEnclosingClass().getSimpleName(), callbacks.getSimpleName(),\n              callbackMethod.name(), ListenerMethod.class.getSimpleName()));\n        }\n        methods.add(method);\n      }\n      return methods;\n    } catch (NoSuchFieldException e) {\n      throw new AssertionError(e);\n    }\n  }\n\n  static String asHumanDescription(Collection<? extends MemberViewBinding> bindings) {\n    Iterator<? extends MemberViewBinding> iterator = bindings.iterator();\n    switch (bindings.size()) {\n      case 1:\n        return iterator.next().getDescription();\n      case 2:\n        return iterator.next().getDescription() + \" and \" + iterator.next().getDescription();","sourceCodeStart":535,"sourceCodeEnd":571,"githubUrl":"https://github.com/JakeWharton/butterknife/blob/fcdebedf3276096db2f51bf6372b849b5a9c75ed/butterknife-compiler/src/main/java/butterknife/compiler/BindingSet.java#L535-L571","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Open the callbacks enum referenced by @ListenerClass(callbacks = ...) and add an @ListenerMethod(name = ..., parameters = ...) annotation to every constant reported in the message","If the constant should not be bound, remove it from the enum or use a enum whose constants all carry @ListenerMethod","If you are not intentionally using callbacks, set @ListenerClass(method = @ListenerMethod(...)) with exactly one method instead of a callbacks enum"],"exampleFix":"// before\npublic enum Callback {\n  CLICK,\n  LONG_CLICK // missing @ListenerMethod\n}\n\n// after\npublic enum Callback {\n  @ListenerMethod(name = \"onClick\", parameters = {View.class})\n  CLICK,\n  @ListenerMethod(name = \"onLongClick\", parameters = {View.class})\n  LONG_CLICK\n}","handlingStrategy":"validation","validationCode":"// At library/test startup, verify every callbacks enum is fully annotated\nvoid verifyListenerCallbacks(Class<? extends Enum<?>> callbacks) {\n  for (Enum<?> constant : callbacks.getEnumConstants()) {\n    Field f = callbacks.getField(constant.name());\n    if (f.getAnnotation(ListenerMethod.class) == null) {\n      throw new IllegalStateException(callbacks + \".\" + constant.name() + \" missing @ListenerMethod\");\n    }\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always annotate every constant of a @ListenerClass callbacks enum with @ListenerMethod","Add a unit test that reflects over your callback enums and asserts @ListenerMethod presence","Copy ButterKnife's own OnItemSelected/OnTextChanged definitions as templates"],"tags":["butterknife","annotation-processing","listener","custom-annotation"],"backgroundTag":null,"analyzedSha":"fcdebedf3276096db2f51bf6372b849b5a9c75ed","analyzedAt":"2026-08-14T10:13:55.083Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}