Netflix/Hystrix · error · UnsupportedOperationException
Unsupported type {}
Error message
Unsupported type {} What it means
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.
Source
Thrown at hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/aop/aspectj/HystrixCommandAspect.java:322
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())) {
builder.defaultGroupKey(defaultProperties.groupKey());
}
if (StringUtils.isNotBlank(defaultProperties.threadPoolKey())) {
builder.defaultThreadPoolKey(defaultProperties.threadPoolKey());
}
}
return builder;
}
View on GitHub (pinned to 5ce3bc58c3)
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.
Example fix
// before
abstract class BaseSvc<T> {
@HystrixCollapser(batchMethod = "getAll")
public abstract Future<T> getById(String id);
}
// after
abstract class BaseSvc<T> {
protected abstract List<T> getAll(List<String> ids);
}
class UserSvc extends BaseSvc<User> {
@HystrixCollapser(batchMethod = "getAll")
public Future<User> getById(String id) { ... }
@HystrixCommand
public List<User> getAll(List<String> ids) { ... }
} Defensive patterns
Strategy: validation
Validate before calling
static boolean isResolvableToClass(java.lang.reflect.Type t) {
return t instanceof Class || (t instanceof java.lang.reflect.ParameterizedType
&& ((java.lang.reflect.ParameterizedType) t).getRawType() instanceof Class);
}
static void assertConcreteGenerics(Method collapser, Method batch) {
java.lang.reflect.Type elem = ((java.lang.reflect.ParameterizedType) batch.getGenericParameterTypes()[0]).getActualTypeArguments()[0];
if (!isResolvableToClass(elem)) throw new IllegalStateException("unresolvable generic on " + batch + ": " + elem);
} Try / catch
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.
Prevention
- 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.
When it happens
Trigger: 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.
Common situations: Generic repository/base-service patterns reused for collapsers; wildcard collection types pulled in from shared API interfaces.
Related errors
- required batch method for collapser is absent, wrong generic
- Return type of batch method must be java.util.List parametri
- Sub type at nesting level %d of %s is expected to be generic
- Collapser method must have one argument: {}
- batch method is absent: {}
AI-assisted analysis of Netflix/Hystrix@5ce3bc58c3 (2026-08-14).
Data as JSON: /api/errors/3c2362276a5859db.
Report an issue: GitHub.