OpenFeign/feign · error · UnsupportedOperationException
SOAP only supports decoding raw types. Found
Error message
SOAP only supports decoding raw types. Found %s
What it means
The jakarta SOAP decoder can only unmarshal the response body into a raw class, because JAXB/SAJ unmarshalling requires a Class. Before decoding, it strips ParameterizedType wrappers (e.g. List<Foo>) to the raw type; if the type is still not a Class (e.g. a generic type variable or wildcard), it throws UnsupportedOperationException. Note generics like List<Foo> are partially handled by taking the raw type, but non-class types are rejected.
Solutions
- Change the Feign method return type to a concrete raw class (or List<ConcreteClass>, which unwraps to List's raw type) instead of a generic type variable or wildcard.
- If you need generics, build a dedicated interface per concrete type or supply a custom Decoder that resolves the type variable before delegating to SOAPDecoder.
Example fix
// before <T> T getOrder(); // after Order getOrder();
Defensive patterns
Strategy: type-guard
Validate before calling
static boolean isSoapDecodable(Type type) {
while (type instanceof ParameterizedType) {
type = ((ParameterizedType) type).getRawType();
}
return type instanceof Class;
} Type guard
if (!isSoapDecodable(methodReturnType)) {
throw new IllegalArgumentException("SOAP method return type must resolve to a raw Class");
} Try / catch
try {
return soapClient.call();
} catch (UnsupportedOperationException e) {
if (e.getMessage() != null && e.getMessage().contains("SOAP only supports decoding raw types")) {
// fix return type to a concrete class
}
throw e;
} Prevention
- Never declare type-variable or wildcard return types on SOAP Feign methods.
- Keep a non-generic interface per concrete SOAP response type.
- Add an archunit/reflection test that asserts all SOAP client method types resolve to Class.
When it happens
Trigger: Declaring a Feign interface method whose return type is not resolvable to a raw Class after unwrapping ParameterizedTypes — e.g. a generic type variable T, wildcard, or generic array — and calling that method so decode() runs on the response.
Common situations: Using a generic client interface with a type variable return type; declaring ResponseEntity-ish wrappers that are not simple parameterized types; copy-pasting a decoder config from the non-generic SOAP module.
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
- SOAP only supports decoding raw types. Found
- SOAP only supports encoding raw types. Found
- SOAP only supports encoding raw types. Found
- JAXB only supports decoding raw types. Found
- Not supported type
AI-assisted analysis of OpenFeign/feign@e2a1e27560 (2026-09-10).
Data as JSON: /api/errors/c9b5ff089d78c450.
Report an issue: GitHub.
Appendix: source
Thrown at soap-jakarta/src/main/java/feign/soap/SOAPDecoder.java:106
this.useFirstChild = false;
}
private SOAPDecoder(Builder builder) {
this.soapProtocol = builder.soapProtocol;
this.jaxbContextFactory = builder.jaxbContextFactory;
this.useFirstChild = builder.useFirstChild;
}
@Override
public Object decode(Response response, Type type) throws IOException {
if (response.status() == 404) 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(
"SOAP only supports decoding raw types. Found " + type);
}
try {
SOAPMessage message =
MessageFactory.newInstance(soapProtocol)
.createMessage(null, response.body().asInputStream());
if (message.getSOAPBody() != null) {
if (message.getSOAPBody().hasFault()) {
throw new SOAPFaultException(message.getSOAPBody().getFault());
}
Unmarshaller unmarshaller = jaxbContextFactory.createUnmarshaller((Class<?>) type);
if (this.useFirstChild) {
return unmarshaller.unmarshal(message.getSOAPBody().getFirstChild());
} else {
return unmarshaller.unmarshal(message.getSOAPBody().extractContentAsDocument());View on GitHub (pinned to e2a1e27560)