{"record":{"id":"f5997a4a8e06ea2a","repo":"OpenFeign/feign","slug":"jaxb-only-supports-decoding-raw-types-found-typ","errorCode":null,"errorMessage":"JAXB only supports decoding raw types. Found ${type}","messagePattern":"JAXB only supports decoding raw types\\. Found (.+?)","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"jaxb-jakarta/src/main/java/feign/jaxb/JAXBDecoder.java","lineNumber":76,"sourceCode":"    this.jaxbContextFactory = jaxbContextFactory;\n    this.namespaceAware = true;\n  }\n\n  private JAXBDecoder(Builder builder) {\n    this.jaxbContextFactory = builder.jaxbContextFactory;\n    this.namespaceAware = builder.namespaceAware;\n  }\n\n  @Override\n  public Object decode(Response response, Type type) throws IOException {\n    if (response.status() == 404 || response.status() == 204) return Util.emptyValueOf(type);\n    if (response.body() == null) return null;\n    while (type instanceof ParameterizedType) {\n      ParameterizedType ptype = (ParameterizedType) type;\n      type = ptype.getRawType();\n    }\n    if (!(type instanceof Class)) {\n      throw new UnsupportedOperationException(\n          \"JAXB only supports decoding raw types. Found \" + type);\n    }\n\n    try {\n      SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();\n      /* Explicitly control sax configuration to prevent XXE attacks */\n      saxParserFactory.setFeature(\"http://xml.org/sax/features/external-general-entities\", false);\n      saxParserFactory.setFeature(\"http://xml.org/sax/features/external-parameter-entities\", false);\n      saxParserFactory.setFeature(\"http://apache.org/xml/features/disallow-doctype-decl\", false);\n      saxParserFactory.setFeature(\n          \"http://apache.org/xml/features/nonvalidating/load-external-dtd\", false);\n      saxParserFactory.setNamespaceAware(namespaceAware);\n\n      return jaxbContextFactory\n          .createUnmarshaller((Class<?>) type)\n          .unmarshal(\n              new SAXSource(\n                  saxParserFactory.newSAXParser().getXMLReader(),","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/OpenFeign/feign/blob/e2a1e27560a1e68840c34f031afca88b36096e30/jaxb-jakarta/src/main/java/feign/jaxb/JAXBDecoder.java#L58-L94","documentation":"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>').","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\npublic interface CrudApi<T> {\n  @Get(\"/{id}\") T get(@Param(\"id\") long id); // T unresolved -> TypeVariable\n}\n// after\npublic interface UserApi {\n  @Get(\"/users/{id}\") UserDto get(@Param(\"id\") long id);\n}\n// or: interface UserApi extends CrudApi<UserDto> {}","handlingStrategy":"type-guard","validationCode":"Type t = method.getGenericReturnType();\nwhile (t instanceof ParameterizedType) t = ((ParameterizedType) t).getRawType();\nif (!(t instanceof Class)) {\n  throw new IllegalStateException(\"JAXBDecoder needs a concrete raw type, got: \" + t);\n}","typeGuard":"static boolean isRawClass(Type t) {\n  while (t instanceof ParameterizedType) t = ((ParameterizedType) t).getRawType();\n  return t instanceof Class;\n}","tryCatchPattern":"try {\n  return decoder.decode(response, type);\n} catch (UnsupportedOperationException e) {\n  if (e.getMessage().startsWith(\"JAXB only supports decoding raw types\")) {\n    throw new IllegalStateException(\"Replace generic return type with a concrete class: \" + e.getMessage(), e);\n  }\n  throw e;\n}","preventionTips":["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"],"tags":["jaxb","xml","generics","feign","decoder"],"backgroundTag":"unsupported-operation","analyzedSha":"e2a1e27560a1e68840c34f031afca88b36096e30","analyzedAt":"2026-09-10T12:37:37.238Z","contentChangedAt":"2026-09-10T12:37:37.238Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}