OpenFeign/feign · error · UnsupportedOperationException
JAXB only supports decoding raw types. Found
Error message
JAXB only supports decoding raw types. Found ${type} What it means
The JAXB (jakarta) decoder can only hand a raw Class to a JAXBContext for unmarshalling. If the declared method return type, after unwrapping all ParameterizedType layers, is not a Class (e.g. a TypeVariable or WildcardType), it throws UnsupportedOperationException('JAXB only supports decoding raw types. Found <type>').
Solutions
- Replace the generic return type with a concrete class: MyDto get() instead of T get()
- Concretize generic interfaces: interface UserApi extends CrudApi<UserDto> so the resolved type is a Class
- If wrapping types are needed (Response<T>, JAXBElement<T>), unwrap to the concrete Class in a custom Decoder before delegating to JAXBDecoder
- Check MethodMetadata.returnType for TypeVariable/WildcardType at startup and fail fast with a clear message
Example fix
// before
public interface CrudApi<T> {
@Get("/{id}") T get(@Param("id") long id); // T unresolved -> TypeVariable
}
// after
public interface UserApi {
@Get("/users/{id}") UserDto get(@Param("id") long id);
}
// or: interface UserApi extends CrudApi<UserDto> {} Defensive patterns
Strategy: type-guard
Validate before calling
Type t = method.getGenericReturnType();
while (t instanceof ParameterizedType) t = ((ParameterizedType) t).getRawType();
if (!(t instanceof Class)) {
throw new IllegalStateException("JAXBDecoder needs a concrete raw type, got: " + t);
} Type guard
static boolean isRawClass(Type t) {
while (t instanceof ParameterizedType) t = ((ParameterizedType) t).getRawType();
return t instanceof Class;
} Try / catch
try {
return decoder.decode(response, type);
} catch (UnsupportedOperationException e) {
if (e.getMessage().startsWith("JAXB only supports decoding raw types")) {
throw new IllegalStateException("Replace generic return type with a concrete class: " + e.getMessage(), e);
}
throw e;
} Prevention
- Avoid TypeVariable/WildcardType return types in Feign interfaces used with JAXB
- Always concretize generic base interfaces (CrudApi<UserDto>, never use the raw generic directly)
- Use @XMLElement-annotated concrete DTO classes as return types
- Validate MethodMetadata.returnType resolves to Class at startup in integration tests
When it happens
Trigger: Declaring a Feign method whose return type resolves to a generic type variable or wildcard - e.g. <T> T get() with T not resolvable, or methods on generic interfaces where the proxy erases to TypeVariable - and decoding with JAXBDecoder.
Common situations: Generic base interfaces (CrudApi<T>) subclassed without concrete types in a way the Contract cannot resolve; returning JAXBElement<T> where T remains a variable; custom Contracts producing unresolved Type objects; JAXBContext caching keyed by such types.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Not supported type
- Not an iterator type
- SOAP only supports decoding raw types. Found
- SOAP only supports decoding raw types. Found
- StreamDecoder supports types other than stream. When type…
AI-assisted analysis of OpenFeign/feign@e2a1e27560 (2026-09-10).
Data as JSON: /api/errors/f5997a4a8e06ea2a.
Report an issue: GitHub.
Appendix: source
Thrown at jaxb-jakarta/src/main/java/feign/jaxb/JAXBDecoder.java:76
this.jaxbContextFactory = jaxbContextFactory;
this.namespaceAware = true;
}
private JAXBDecoder(Builder builder) {
this.jaxbContextFactory = builder.jaxbContextFactory;
this.namespaceAware = builder.namespaceAware;
}
@Override
public Object decode(Response response, Type type) throws IOException {
if (response.status() == 404 || response.status() == 204) return Util.emptyValueOf(type);
if (response.body() == null) return null;
while (type instanceof ParameterizedType) {
ParameterizedType ptype = (ParameterizedType) type;
type = ptype.getRawType();
}
if (!(type instanceof Class)) {
throw new UnsupportedOperationException(
"JAXB only supports decoding raw types. Found " + type);
}
try {
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
/* Explicitly control sax configuration to prevent XXE attacks */
saxParserFactory.setFeature("http://xml.org/sax/features/external-general-entities", false);
saxParserFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
saxParserFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", false);
saxParserFactory.setFeature(
"http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
saxParserFactory.setNamespaceAware(namespaceAware);
return jaxbContextFactory
.createUnmarshaller((Class<?>) type)
.unmarshal(
new SAXSource(
saxParserFactory.newSAXParser().getXMLReader(),View on GitHub (pinned to e2a1e27560)