OpenFeign/feign · error · DecodeException

${e.toString()}

Error message

${e.toString()}

What it means

Same failure as the jakarta variant: JAXBDecoder catches JAXBException/ParserConfigurationException/SAXException during SAX-based unmarshalling and rethrows them as DecodeException with e.toString(). It indicates the response body could not be parsed or bound to the target JAXB class.

Solutions

  1. Inspect e.getCause() to distinguish parse failures from binding failures.
  2. Confirm the server returns XML matching the declared return type (root element, namespaces).
  3. Ensure DTOs are JAXB-annotated and registered with the JAXBContextFactory.
  4. Catch DecodeException and handle non-XML (e.g. HTML) error responses.

Example fix

// before
Item i = api.get();
// after
try { Item i = api.get(); }
catch (DecodeException e) { log.warn("bad xml: {}", String.valueOf(e.getCause())); }
Defensive patterns

Strategy: try-catch

Validate before calling

// before decoding
if (response.status() >= 400) { /* handle error response before decoding body */ }

Try / catch

try {
  result = client.call();
} catch (DecodeException e) {
  if (e.getCause() instanceof SAXException) { /* malformed XML */ }
  else if (e.getCause() instanceof JAXBException) { /* mapping mismatch */ }
  else { throw e; }
}

Prevention

When it happens

Trigger: Response body is not well-formed XML, root element/namespaces do not match the expected @XmlRootElement type, or SAX parser/stream failure while decoding.

Common situations: HTML error pages from gateways; XML namespace mismatches between response and DTOs; missing @XmlRootElement causing JAXBException; truncated responses.

Related errors


AI-assisted analysis of OpenFeign/feign@e2a1e27560 (2026-09-10). Data as JSON: /api/errors/b8bd5545084a83f0. Report an issue: GitHub.

Appendix: source

Thrown at jaxb/src/main/java/feign/jaxb/JAXBDecoder.java:97

    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(),
                  new InputSource(response.body().asInputStream())));
    } catch (JAXBException | ParserConfigurationException | SAXException e) {
      throw new DecodeException(response.status(), e.toString(), response.request(), e);
    } finally {
      if (response.body() != null) {
        response.body().close();
      }
    }
  }

  public static class Builder {
    private boolean namespaceAware = true;
    private JAXBContextFactory jaxbContextFactory;

    /** Controls whether the underlying XML parser is namespace aware. Default is true. */
    public Builder withNamespaceAware(boolean namespaceAware) {
      this.namespaceAware = namespaceAware;
      return this;
    }

    public Builder withJAXBContextFactory(JAXBContextFactory jaxbContextFactory) {

View on GitHub (pinned to e2a1e27560)