{"record":{"id":"5e0061f775f23dbe","repo":"Netflix/Hystrix","slug":"method-cannot-be-annotated-with-hystrixcommand-and","errorCode":null,"errorMessage":"method cannot be annotated with HystrixCommand and HystrixCollapser annotations at the same time","messagePattern":"method cannot be annotated with HystrixCommand and HystrixCollapser annotations at the same time","errorType":"validation","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/aop/aspectj/HystrixCommandAspect.java","lineNumber":91,"sourceCode":"                .put(HystrixPointcutType.COLLAPSER, new CollapserMetaHolderFactory())\n                .build();\n    }\n\n    @Pointcut(\"@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand)\")\n\n    public void hystrixCommandAnnotationPointcut() {\n    }\n\n    @Pointcut(\"@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser)\")\n    public void hystrixCollapserAnnotationPointcut() {\n    }\n\n    @Around(\"hystrixCommandAnnotationPointcut() || hystrixCollapserAnnotationPointcut()\")\n    public Object methodsAnnotatedWithHystrixCommand(final ProceedingJoinPoint joinPoint) throws Throwable {\n        Method method = getMethodFromTarget(joinPoint);\n        Validate.notNull(method, \"failed to get method from joinPoint: %s\", joinPoint);\n        if (method.isAnnotationPresent(HystrixCommand.class) && method.isAnnotationPresent(HystrixCollapser.class)) {\n            throw new IllegalStateException(\"method cannot be annotated with HystrixCommand and HystrixCollapser \" +\n                    \"annotations at the same time\");\n        }\n        MetaHolderFactory metaHolderFactory = META_HOLDER_FACTORY_MAP.get(HystrixPointcutType.of(method));\n        MetaHolder metaHolder = metaHolderFactory.create(joinPoint);\n        HystrixInvokable invokable = HystrixCommandFactory.getInstance().create(metaHolder);\n        ExecutionType executionType = metaHolder.isCollapserAnnotationPresent() ?\n                metaHolder.getCollapserExecutionType() : metaHolder.getExecutionType();\n\n        Object result;\n        try {\n            if (!metaHolder.isObservable()) {\n                result = CommandExecutor.execute(invokable, executionType, metaHolder);\n            } else {\n                result = executeObservable(invokable, executionType, metaHolder);\n            }\n        } catch (HystrixBadRequestException e) {\n            throw e.getCause() != null ? e.getCause() : e;\n        } catch (HystrixRuntimeException e) {","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/Netflix/Hystrix/blob/5ce3bc58c38e7ca60ef2fe0e516e390e294ad941/hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/aop/aspectj/HystrixCommandAspect.java#L73-L109","documentation":"Hystrix Javanica's AspectJ aspect intercepts methods annotated with either @HystrixCommand or @HystrixCollapser, but a single method must not carry both. The two annotations build completely different command pipelines (a plain wrapped command vs. a request-batching collapser delegating to a batch method), so the aspect refuses to guess and throws IllegalStateException at the first intercepted call.","triggerScenarios":"Any method annotated with both @HystrixCommand and @HystrixCollapser, invoked through the aspect (Spring bean woven by HystrixCommandAspect). The check runs in methodsAnnotatedWithHystrixCommand before any MetaHolderFactory work.","commonSituations":"Copy-pasting a @HystrixCollapser method from an example onto an existing @HystrixCommand method; IDE auto-import picking the wrong annotation and stacking them during refactoring.","solutions":["Remove one of the two annotations from the method — they are mutually exclusive by design.","If you want collapsing, keep only @HystrixCollapser on the single-argument method and move the @HystrixCommand onto the batchMethod it references.","If you want a plain command, delete @HystrixCollapser and keep @HystrixCommand."],"exampleFix":"// before\n@HystrixCommand\n@HystrixCollapser(batchMethod = \"getUserByIds\")\npublic Future<User> getUserById(String id) { ... }\n\n// after\n@HystrixCollapser(batchMethod = \"getUserByIds\")\npublic Future<User> getUserById(String id) { ... }\n\n@HystrixCommand\npublic List<User> getUserByIds(List<String> ids) { ... }","handlingStrategy":"validation","validationCode":"static void assertSingleAnnotation(Method m) {\n    boolean cmd = m.isAnnotationPresent(com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand.class);\n    boolean col = m.isAnnotationPresent(com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser.class);\n    if (cmd && col) throw new IllegalArgumentException(m + \" has both @HystrixCommand and @HystrixCollapser\");\n}","typeGuard":null,"tryCatchPattern":"catch (IllegalStateException e) when message starts with 'method cannot be annotated' -> treat as a startup/config defect: fail the deploy, log the method name, fix the annotations. Do not swallow.","preventionTips":["Run an ArchUnit or reflection-based startup check that every @HystrixCommand/@HystrixCollapser method has exactly one of the two annotations.","Code-review rule: @HystrixCollapser belongs on single-arg request methods; @HystrixCommand on the batch method — never both on one method."],"tags":["hystrix","javanica","annotation","aop","misuse"],"backgroundTag":null,"analyzedSha":"5ce3bc58c38e7ca60ef2fe0e516e390e294ad941","analyzedAt":"2026-08-14T10:55:35.600Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}