{"record":{"id":"3c2362276a5859db","repo":"Netflix/Hystrix","slug":"unsupported-type","errorCode":null,"errorMessage":"Unsupported type {}","messagePattern":"Unsupported type (.+?)","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/aop/aspectj/HystrixCommandAspect.java","lineNumber":322,"sourceCode":"        return getFirstGenericParameter(type, 1);\n    }\n\n    private static Class<?> getFirstGenericParameter(final Type type, final int nestedDepth) {\n        int cDepth = 0;\n        Type tType = type;\n\n        for (int cDept = 0; cDept < nestedDepth; cDept++) {\n            if (!(tType instanceof ParameterizedType))\n                throw new IllegalStateException(String.format(\"Sub type at nesting level %d of %s is expected to be generic\", cDepth, type));\n            tType = ((ParameterizedType) tType).getActualTypeArguments()[cDept];\n        }\n\n        if (tType instanceof ParameterizedType)\n            return (Class<?>) ((ParameterizedType) tType).getRawType();\n        else if (tType instanceof Class)\n            return (Class<?>) tType;\n\n        throw new UnsupportedOperationException(\"Unsupported type \" + tType);\n    }\n\n    private static MetaHolder.Builder setDefaultProperties(MetaHolder.Builder builder, Class<?> declaringClass, final ProceedingJoinPoint joinPoint) {\n        Optional<DefaultProperties> defaultPropertiesOpt = AopUtils.getAnnotation(joinPoint, DefaultProperties.class);\n        builder.defaultGroupKey(declaringClass.getSimpleName());\n        if (defaultPropertiesOpt.isPresent()) {\n            DefaultProperties defaultProperties = defaultPropertiesOpt.get();\n            builder.defaultProperties(defaultProperties);\n            if (StringUtils.isNotBlank(defaultProperties.groupKey())) {\n                builder.defaultGroupKey(defaultProperties.groupKey());\n            }\n            if (StringUtils.isNotBlank(defaultProperties.threadPoolKey())) {\n                builder.defaultThreadPoolKey(defaultProperties.threadPoolKey());\n            }\n        }\n        return builder;\n    }\n","sourceCodeStart":304,"sourceCodeEnd":340,"githubUrl":"https://github.com/Netflix/Hystrix/blob/5ce3bc58c38e7ca60ef2fe0e516e390e294ad941/hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/aop/aspectj/HystrixCommandAspect.java#L304-L340","documentation":"The terminal fallback of getFirstGenericParameter: after resolving the requested nesting depth, the resulting Type is neither a ParameterizedType nor a Class. Java reflection can return TypeVariable (unresolved generic like <T>), WildcardType (? extends X), or GenericArrayType, none of which Javanica can reduce to a concrete Class for building the collapser, so it throws UnsupportedOperationException.","triggerScenarios":"Collapser or batch method declared with unresolved type variables, e.g. <T> Future<T> getById(T id) or List<? extends User>; a generic base class exposing the batch method where T is never bound to a concrete class at the call site.","commonSituations":"Generic repository/base-service patterns reused for collapsers; wildcard collection types pulled in from shared API interfaces.","solutions":["Bind generics to concrete classes on collapser/batch methods (no <T>, no wildcards): Future<User> getUserById(String id).","Do not put @HystrixCollapser on generic base-class methods; write a concrete leaf-class method per collapsed operation.","Replace List<? extends User> with List<User> on the batch method."],"exampleFix":"// before\nabstract class BaseSvc<T> {\n    @HystrixCollapser(batchMethod = \"getAll\")\n    public abstract Future<T> getById(String id);\n}\n\n// after\nabstract class BaseSvc<T> {\n    protected abstract List<T> getAll(List<String> ids);\n}\nclass UserSvc extends BaseSvc<User> {\n    @HystrixCollapser(batchMethod = \"getAll\")\n    public Future<User> getById(String id) { ... }\n    @HystrixCommand\n    public List<User> getAll(List<String> ids) { ... }\n}","handlingStrategy":"validation","validationCode":"static boolean isResolvableToClass(java.lang.reflect.Type t) {\n    return t instanceof Class || (t instanceof java.lang.reflect.ParameterizedType\n            && ((java.lang.reflect.ParameterizedType) t).getRawType() instanceof Class);\n}\nstatic void assertConcreteGenerics(Method collapser, Method batch) {\n    java.lang.reflect.Type elem = ((java.lang.reflect.ParameterizedType) batch.getGenericParameterTypes()[0]).getActualTypeArguments()[0];\n    if (!isResolvableToClass(elem)) throw new IllegalStateException(\"unresolvable generic on \" + batch + \": \" + elem);\n}","typeGuard":null,"tryCatchPattern":"try/catch UnsupportedOperationException with message 'Unsupported type' during collapser setup → log the offending Type (TypeVariable/wildcard) and fail the build; do not retry at runtime.","preventionTips":["Never declare collapser or batch methods with unbound type variables or wildcards; bind to concrete classes in leaf classes.","Keep @HystrixCollapser off generic base-class API surfaces; write per-entity collapsers."],"tags":["hystrix","javanica","generics","reflection","collapser"],"backgroundTag":null,"analyzedSha":"5ce3bc58c38e7ca60ef2fe0e516e390e294ad941","analyzedAt":"2026-08-14T10:55:35.600Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}