Netflix/Hystrix · error · IllegalStateException

Sub type at nesting level %d of %s is expected to be generic

Error message

Sub type at nesting level %d of %s is expected to be generic

What it means

Thrown by getFirstGenericParameter while walking generic types for a @HystrixCollapser pair: at the requested nesting depth the Type is not a ParameterizedType. Practically this means a raw type was used where a parameterized one is required — most commonly a batch method declared with a raw List (no <T>) or an unparameterized Future/Observable return.

Source

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

        }
    }

    private static Method getAjcMethodFromTarget(JoinPoint joinPoint) {
        return getAjcMethodAroundAdvice(joinPoint.getTarget().getClass(), (MethodSignature) joinPoint.getSignature());
    }


    private static Class<?> getFirstGenericParameter(Type type) {
        return getFirstGenericParameter(type, 1);
    }

    private static Class<?> getFirstGenericParameter(final Type type, final int nestedDepth) {
        int cDepth = 0;
        Type tType = type;

        for (int cDept = 0; cDept < nestedDepth; cDept++) {
            if (!(tType instanceof ParameterizedType))
                throw new IllegalStateException(String.format("Sub type at nesting level %d of %s is expected to be generic", cDepth, type));
            tType = ((ParameterizedType) tType).getActualTypeArguments()[cDept];
        }

        if (tType instanceof ParameterizedType)
            return (Class<?>) ((ParameterizedType) tType).getRawType();
        else if (tType instanceof Class)
            return (Class<?>) tType;

        throw new UnsupportedOperationException("Unsupported type " + tType);
    }

    private static MetaHolder.Builder setDefaultProperties(MetaHolder.Builder builder, Class<?> declaringClass, final ProceedingJoinPoint joinPoint) {
        Optional<DefaultProperties> defaultPropertiesOpt = AopUtils.getAnnotation(joinPoint, DefaultProperties.class);
        builder.defaultGroupKey(declaringClass.getSimpleName());
        if (defaultPropertiesOpt.isPresent()) {
            DefaultProperties defaultProperties = defaultPropertiesOpt.get();
            builder.defaultProperties(defaultProperties);
            if (StringUtils.isNotBlank(defaultProperties.groupKey())) {

View on GitHub (pinned to 5ce3bc58c3)

Solutions

  1. Parameterize the batch method: public List<User> getUserByIds(List<String> ids) instead of raw List.
  2. Parameterize the collapser's return type: Future<User>, not raw Future.
  3. Treat raw-type compiler warnings on collapser/batch methods as errors in your build.

Example fix

// before
@HystrixCommand
public List getUserByIds(List ids) { ... }

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

Strategy: validation

Validate before calling

static void assertParameterizedTypes(Method collapser, Method batch) {
    if (!(batch.getGenericParameterTypes()[0] instanceof java.lang.reflect.ParameterizedType))
        throw new IllegalStateException(batch + " uses raw List — parameterize it");
    java.lang.reflect.Type rt = collapser.getGenericReturnType();
    if (rt instanceof Class && collapser.getReturnType() == java.util.concurrent.Future.class)
        throw new IllegalStateException(collapser + " returns raw Future — parameterize it");
}

Try / catch

Catch IllegalStateException during collapser wiring tests; message 'expected to be generic' (nesting level always prints 0 due to a display bug) → fix the raw type declaration; rethrow otherwise.

Prevention

When it happens

Trigger: Batch method signature public List getUserByIds(List ids) (raw types, e.g. ported pre-generics code); collapser returning raw Future; any place Javanica must read the element type of List/Future/Observable but the declaration omitted type arguments. The 'cDepth' in the message is always 0 (a known cosmetic bug — the loop variable cDept is never printed), which can mislead debugging.

Common situations: Migrating legacy Java 1.4-style service methods into collapsers; IDE raw-type warnings ignored; decompiled or generated code dropping generic signatures.

Related errors


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