Netflix/Hystrix · error · IllegalStateException

method cannot be annotated with HystrixCommand and HystrixCo

Error message

method cannot be annotated with HystrixCommand and HystrixCollapser annotations at the same time

What it means

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.

Source

Thrown at hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/aop/aspectj/HystrixCommandAspect.java:91

                .put(HystrixPointcutType.COLLAPSER, new CollapserMetaHolderFactory())
                .build();
    }

    @Pointcut("@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand)")

    public void hystrixCommandAnnotationPointcut() {
    }

    @Pointcut("@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser)")
    public void hystrixCollapserAnnotationPointcut() {
    }

    @Around("hystrixCommandAnnotationPointcut() || hystrixCollapserAnnotationPointcut()")
    public Object methodsAnnotatedWithHystrixCommand(final ProceedingJoinPoint joinPoint) throws Throwable {
        Method method = getMethodFromTarget(joinPoint);
        Validate.notNull(method, "failed to get method from joinPoint: %s", joinPoint);
        if (method.isAnnotationPresent(HystrixCommand.class) && method.isAnnotationPresent(HystrixCollapser.class)) {
            throw new IllegalStateException("method cannot be annotated with HystrixCommand and HystrixCollapser " +
                    "annotations at the same time");
        }
        MetaHolderFactory metaHolderFactory = META_HOLDER_FACTORY_MAP.get(HystrixPointcutType.of(method));
        MetaHolder metaHolder = metaHolderFactory.create(joinPoint);
        HystrixInvokable invokable = HystrixCommandFactory.getInstance().create(metaHolder);
        ExecutionType executionType = metaHolder.isCollapserAnnotationPresent() ?
                metaHolder.getCollapserExecutionType() : metaHolder.getExecutionType();

        Object result;
        try {
            if (!metaHolder.isObservable()) {
                result = CommandExecutor.execute(invokable, executionType, metaHolder);
            } else {
                result = executeObservable(invokable, executionType, metaHolder);
            }
        } catch (HystrixBadRequestException e) {
            throw e.getCause() != null ? e.getCause() : e;
        } catch (HystrixRuntimeException e) {

View on GitHub (pinned to 5ce3bc58c3)

Solutions

  1. Remove one of the two annotations from the method — they are mutually exclusive by design.
  2. If you want collapsing, keep only @HystrixCollapser on the single-argument method and move the @HystrixCommand onto the batchMethod it references.
  3. If you want a plain command, delete @HystrixCollapser and keep @HystrixCommand.

Example fix

// before
@HystrixCommand
@HystrixCollapser(batchMethod = "getUserByIds")
public Future<User> getUserById(String id) { ... }

// after
@HystrixCollapser(batchMethod = "getUserByIds")
public Future<User> getUserById(String id) { ... }

@HystrixCommand
public List<User> getUserByIds(List<String> ids) { ... }
Defensive patterns

Strategy: validation

Validate before calling

static void assertSingleAnnotation(Method m) {
    boolean cmd = m.isAnnotationPresent(com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand.class);
    boolean col = m.isAnnotationPresent(com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser.class);
    if (cmd && col) throw new IllegalArgumentException(m + " has both @HystrixCommand and @HystrixCollapser");
}

Try / catch

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.

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of Netflix/Hystrix@5ce3bc58c3 (2026-08-14). Data as JSON: /api/errors/5e0061f775f23dbe. Report an issue: GitHub.