Netflix/Hystrix · error · IllegalStateException

Collapser method must have one argument: {}

Error message

Collapser method must have one argument: {}

What it means

A @HystrixCollapser method must take exactly one argument. The collapser's contract is that each call contributes its single argument as one element of the List that is eventually passed to the batch method, so zero or multiple parameters make request collapsing undefined and CollapserMetaHolderFactory throws IllegalStateException during meta-holder creation.

Source

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

        MetaHolder.Builder metaHolderBuilder(Object proxy, Method method, Object obj, Object[] args, final ProceedingJoinPoint joinPoint) {
            MetaHolder.Builder builder = MetaHolder.builder()
                    .args(args).method(method).obj(obj).proxyObj(proxy)
                    .joinPoint(joinPoint);

            setFallbackMethod(builder, obj.getClass(), method);
            builder = setDefaultProperties(builder, obj.getClass(), joinPoint);
            return builder;
        }
    }

    private static class CollapserMetaHolderFactory extends MetaHolderFactory {

        @Override
        public MetaHolder create(Object proxy, Method collapserMethod, Object obj, Object[] args, final ProceedingJoinPoint joinPoint) {
            HystrixCollapser hystrixCollapser = collapserMethod.getAnnotation(HystrixCollapser.class);
            if (collapserMethod.getParameterTypes().length > 1 || collapserMethod.getParameterTypes().length == 0) {
                throw new IllegalStateException("Collapser method must have one argument: " + collapserMethod);
            }

            Method batchCommandMethod = getDeclaredMethod(obj.getClass(), hystrixCollapser.batchMethod(), List.class);

            if (batchCommandMethod == null)
                throw new IllegalStateException("batch method is absent: " + hystrixCollapser.batchMethod());

            Class<?> batchReturnType = batchCommandMethod.getReturnType();
            Class<?> collapserReturnType = collapserMethod.getReturnType();
            boolean observable = collapserReturnType.equals(Observable.class);

            if (!collapserMethod.getParameterTypes()[0]
                    .equals(getFirstGenericParameter(batchCommandMethod.getGenericParameterTypes()[0]))) {
                throw new IllegalStateException("required batch method for collapser is absent, wrong generic type: expected "
                        + obj.getClass().getCanonicalName() + "." +
                        hystrixCollapser.batchMethod() + "(java.util.List<" + collapserMethod.getParameterTypes()[0] + ">), but it's " +
                        getFirstGenericParameter(batchCommandMethod.getGenericParameterTypes()[0]));
            }

View on GitHub (pinned to 5ce3bc58c3)

Solutions

  1. Reduce the collapser method to exactly one parameter and fold extra context into that parameter (a small value object) or into the command's groupKey/properties.
  2. If you need multiple independent arguments, use a plain @HystrixCommand instead of a collapser.
  3. Verify the batch method's List element type still matches the (new) single parameter type.

Example fix

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

// after
@HystrixCollapser(batchMethod = "getUserByIds")
public Future<User> getUserById(UserRequest req) { ... }  // UserRequest carries id + tenant
Defensive patterns

Strategy: validation

Validate before calling

static void assertCollapserSignature(Method m) {
    if (!m.isAnnotationPresent(HystrixCollapser.class)) return;
    int n = m.getParameterTypes().length;
    if (n != 1) throw new IllegalArgumentException(m + " must have exactly one parameter, has " + n);
}

Try / catch

Wrap first collapser invocation in a smoke test / startup probe with try { ... } catch (IllegalStateException e) { fail fast with the collapser method name in the message }; configuration errors should crash tests, not production calls.

Prevention

When it happens

Trigger: Calling a @HystrixCollapser-annotated method whose signature has 0 parameters or more than 1 parameter (e.g. getUserById(String id, String tenant)). The check fires before the batch method is even looked up.

Common situations: Adding a second parameter (timeout, tenant id, locale) to an existing collapser method later; writing a collapser around a no-arg lookup method.

Related errors


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