{"record":{"id":"ec8a01bf563adc8f","repo":"greenrobot/EventBus","slug":"methodname-is-a-illegal-subscribe-method-must","errorCode":null,"errorMessage":"${methodName} is a illegal @Subscribe method: must be public, non-static, and non-abstract","messagePattern":"(.+?) is a illegal @Subscribe method: must be public, non-static, and non-abstract","errorType":"exception","errorClass":"EventBusException","httpStatus":null,"severity":"error","filePath":"EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java","lineNumber":191,"sourceCode":"                Class<?>[] parameterTypes = method.getParameterTypes();\n                if (parameterTypes.length == 1) {\n                    Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);\n                    if (subscribeAnnotation != null) {\n                        Class<?> eventType = parameterTypes[0];\n                        if (findState.checkAdd(method, eventType)) {\n                            ThreadMode threadMode = subscribeAnnotation.threadMode();\n                            findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,\n                                    subscribeAnnotation.priority(), subscribeAnnotation.sticky()));\n                        }\n                    }\n                } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {\n                    String methodName = method.getDeclaringClass().getName() + \".\" + method.getName();\n                    throw new EventBusException(\"@Subscribe method \" + methodName +\n                            \"must have exactly 1 parameter but has \" + parameterTypes.length);\n                }\n            } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {\n                String methodName = method.getDeclaringClass().getName() + \".\" + method.getName();\n                throw new EventBusException(methodName +\n                        \" is a illegal @Subscribe method: must be public, non-static, and non-abstract\");\n            }\n        }\n    }\n\n    static void clearCaches() {\n        METHOD_CACHE.clear();\n    }\n\n    static class FindState {\n        final List<SubscriberMethod> subscriberMethods = new ArrayList<>();\n        final Map<Class, Object> anyMethodByEventType = new HashMap<>();\n        final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();\n        final StringBuilder methodKeyBuilder = new StringBuilder(128);\n\n        Class<?> subscriberClass;\n        Class<?> clazz;\n        boolean skipSuperClasses;","sourceCodeStart":173,"sourceCodeEnd":209,"githubUrl":"https://github.com/greenrobot/EventBus/blob/0194926b3bcf70cc0d7bfd3c5da16708dd5ab876/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java#L173-L209","documentation":"Thrown during method verification in SubscriberMethodFinder when strictMethodVerification is enabled and a method carries @Subscribe but its modifiers fail the check (modifiers & Modifier.PUBLIC) == 0 or (modifiers & MODIFIERS_IGNORE) != 0, i.e. the method is not public, or is static/abstract (MODIFIERS_IGNORE covers static, abstract, and synthetic/bridge). EventBus invokes handlers via Method.invoke on the public method; non-public, static, or abstract methods cannot serve as instance handlers.","triggerScenarios":"Annotating a private, protected, or package-private handler; annotating a static method (often a util 'handler'); annotating an abstract method in a base class that concrete subclasses implement; registering the class triggers the scan and throws.","commonSituations":"Kotlin functions default to public so this mostly hits Java code with visibility reductions after refactoring; abstract base-class handler contracts; IDE auto-generating static helper overloads; deliberate encapsulation (private handlers) by teams unaware EventBus requires public.","solutions":["Make the handler method public and non-static: public void onEvent(MessageEvent event)","For abstract contracts, remove @Subscribe from the abstract method and annotate each concrete public override instead","For static helpers, move the annotation to a public instance method that delegates"],"exampleFix":"// before\n@Subscribe\nprotected void onMessage(MessageEvent event) { ... } // not public -> throws\n\n// after\n@Subscribe\npublic void onMessage(MessageEvent event) { ... }","handlingStrategy":"validation","validationCode":"for (Method m : subscriberClass.getDeclaredMethods()) {\n    Subscribe ann = m.getAnnotation(Subscribe.class);\n    if (ann != null) {\n        int mod = m.getModifiers();\n        if (!Modifier.isPublic(mod) || Modifier.isStatic(mod) || Modifier.isAbstract(mod)) {\n            throw new IllegalStateException(\"@Subscribe method \" + m + \" must be public, non-static, non-abstract\");\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep handlers public instance methods; in Java avoid package-private 'encapsulation' on handlers","Don't annotate abstract base methods; annotate the concrete overrides"],"tags":["eventbus","annotation","visibility","method-modifiers","validation"],"backgroundTag":null,"analyzedSha":"0194926b3bcf70cc0d7bfd3c5da16708dd5ab876","analyzedAt":"2026-08-14T10:41:08.786Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}