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

  1. Replace the generic return type with a concrete class: MyDto get() instead of T get()
  2. Concretize generic interfaces: interface UserApi extends CrudApi<UserDto> so the resolved type is a Class
  3. If wrapping types are needed (Response<T>, JAXBElement<T>), unwrap to the concrete Class in a custom Decoder before delegating to JAXBDecoder
  4. 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

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


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)