{"record":{"id":"fd6a7e6f6f0944b4","repo":"JakeWharton/butterknife","slug":"no-s-defined-on-s","errorCode":null,"errorMessage":"No @%s defined on @%s.","messagePattern":"No @(.+?) defined on @(.+?)\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"butterknife-compiler/src/main/java/butterknife/compiler/ButterKnifeProcessor.java","lineNumber":1080,"sourceCode":"    int[] ids = (int[]) annotationValue.invoke(annotation);\n    String name = executableElement.getSimpleName().toString();\n    boolean required = isListenerRequired(executableElement);\n\n    // Verify that the method and its containing class are accessible via generated code.\n    boolean hasError = isInaccessibleViaGeneratedCode(annotationClass, \"methods\", element);\n    hasError |= isBindingInWrongPackage(annotationClass, element);\n\n    Integer duplicateId = findDuplicate(ids);\n    if (duplicateId != null) {\n      error(element, \"@%s annotation for method contains duplicate ID %d. (%s.%s)\",\n          annotationClass.getSimpleName(), duplicateId, enclosingElement.getQualifiedName(),\n          element.getSimpleName());\n      hasError = true;\n    }\n\n    ListenerClass listener = annotationClass.getAnnotation(ListenerClass.class);\n    if (listener == null) {\n      throw new IllegalStateException(\n          String.format(\"No @%s defined on @%s.\", ListenerClass.class.getSimpleName(),\n              annotationClass.getSimpleName()));\n    }\n\n    for (int id : ids) {\n      if (id == NO_ID.value) {\n        if (ids.length == 1) {\n          if (!required) {\n            error(element, \"ID-free binding must not be annotated with @Optional. (%s.%s)\",\n                enclosingElement.getQualifiedName(), element.getSimpleName());\n            hasError = true;\n          }\n        } else {\n          error(element, \"@%s annotation contains invalid ID %d. (%s.%s)\",\n              annotationClass.getSimpleName(), id, enclosingElement.getQualifiedName(),\n              element.getSimpleName());\n          hasError = true;\n        }","sourceCodeStart":1062,"sourceCodeEnd":1098,"githubUrl":"https://github.com/JakeWharton/butterknife/blob/fcdebedf3276096db2f51bf6372b849b5a9c75ed/butterknife-compiler/src/main/java/butterknife/compiler/ButterKnifeProcessor.java#L1062-L1098","documentation":"The processor recognizes a listener annotation by looking for the @ListenerClass meta-annotation on it, which supplies the target setter method, listener type, and so on. If a listener annotation is processed (typically because it was placed on a method and reached parseListenerAnnotation) but carries no @ListenerClass, this IllegalStateException is thrown. It means the annotation looks like a ButterKnife listener but lacks the metadata the processor needs.","triggerScenarios":"Creating an annotation with a name or package that causes it to be routed to parseListenerAnnotation (e.g. registered via the processor's supported lists) without meta-annotating it with @ListenerClass; deleting the @ListenerClass line while refactoring a custom listener annotation.","commonSituations":"Writing a custom ButterKnife listener extension for the first time; copy-pasting an annotation class and stripping what looked like an unnecessary meta-annotation.","solutions":["Add @ListenerClass(...) to the annotation with targetType, setter, type, and either method or callbacks filled in","If the annotation is not meant to be a ButterKnife listener, remove it from the method or from the set of annotations processed by ButterKnifeProcessor"],"exampleFix":"// before\npublic @interface OnCustomEvent {\n  int[] value();\n}\n\n// after\n@ListenerClass(\n    targetType = \"android.widget.CustomView\",\n    setter = \"setCustomListener\",\n    type = \"com.example.CustomListener\",\n    method = @ListenerMethod(name = \"onCustom\", parameters = {View.class}))\npublic @interface OnCustomEvent {\n  int[] value();\n}","handlingStrategy":"validation","validationCode":"if (MyListener.class.getAnnotation(ListenerClass.class) == null) {\n  throw new IllegalStateException(\"MyListener is missing @ListenerClass\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat @ListenerClass as mandatory metadata for any ButterKnife listener annotation","Write one unit test per custom annotation asserting getAnnotation(ListenerClass.class) != null"],"tags":["butterknife","annotation-processing","custom-annotation","metadata"],"backgroundTag":null,"analyzedSha":"fcdebedf3276096db2f51bf6372b849b5a9c75ed","analyzedAt":"2026-08-14T10:13:55.083Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}