spring-projects/spring-security · error · Saml2Exception

Failed to deserialize payload

Error message

Failed to deserialize payload

What it means

OpenSaml5Template.deserialize(String) wraps any non-Saml2Exception failure while parsing/unmarshalling the payload into Saml2Exception('Failed to deserialize payload') with the original as cause. This covers XML parse errors (malformed XML), IO errors from the ParserPool, and unmarshalling runtime exceptions.

Source

Thrown at saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/web/OpenSaml5Template.java:160

	@Override
	public <T extends XMLObject> T deserialize(InputStream serialized) {
		try {
			ParserPool pool = XMLObjectProviderRegistrySupport.getParserPool();
			Assert.notNull(pool, "ParserPool must be configured");
			Document document = pool.parse(serialized);
			Element element = document.getDocumentElement();
			UnmarshallerFactory factory = XMLObjectProviderRegistrySupport.getUnmarshallerFactory();
			Unmarshaller unmarshaller = factory.getUnmarshaller(element);
			if (unmarshaller == null) {
				throw new Saml2Exception("Unsupported element of type " + element.getTagName());
			}
			return (T) unmarshaller.unmarshall(element);
		}
		catch (Saml2Exception ex) {
			throw ex;
		}
		catch (Exception ex) {
			throw new Saml2Exception("Failed to deserialize payload", ex);
		}
	}

	@Override
	public OpenSaml5SerializationConfigurer serialize(XMLObject object) {
		Marshaller marshaller = XMLObjectProviderRegistrySupport.getMarshallerFactory().getMarshaller(object);
		Assert.notNull(marshaller, "Marshaller for " + object.getElementQName() + " must be configured");
		try {
			return serialize(marshaller.marshall(object));
		}
		catch (MarshallingException ex) {
			throw new Saml2Exception(ex);
		}
	}

	@Override
	public OpenSaml5SerializationConfigurer serialize(Element element) {
		return new OpenSaml5SerializationConfigurer(element);

View on GitHub (pinned to 96852e8860)

Solutions

  1. Base64-decode the SAMLResponse/SAMLRequest parameter before deserializing
  2. Check the cause chain (ex.getCause()) to distinguish XML syntax errors from unmarshalling errors
  3. Inspect raw bytes of the payload for HTML error pages, truncation, or wrong encoding
  4. Verify the message was not double URL-encoded/decoded through redirects

Example fix

// before
template.deserialize(request.getParameter("SAMLResponse")); // still base64
// after
String xml = new String(Base64.getMimeDecoder().decode(request.getParameter("SAMLResponse")), StandardCharsets.UTF_8);
template.deserialize(xml);
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-validate that payload decodes to well-formed XML
byte[] raw = Base64.getMimeDecoder().decode(samlParameter);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
dbf.newDocumentBuilder().parse(new InputSource(new StringReader(new String(raw, StandardCharsets.UTF_8))));

Try / catch

try {
    return template.deserialize(serialized);
} catch (Saml2Exception ex) {
    logger.warn("SAML payload deserialize failed", ex.getCause());
    throw new Saml2AuthenticationException(Saml2ErrorCodes.INVALID_RESPONSE, "Malformed SAML payload", ex);
}

Prevention

When it happens

Trigger: deserialize() receives input that cannot be parsed as XML (truncated/base64-decoding issues upstream, HTML error pages, invalid characters) or the unmarshaller itself fails mid-unmarshall.

Common situations: Sending the base64-encoded parameter without decoding it before calling deserialize; SAML POST binding payloads corrupted by URL-decoding; IdP returned an HTML error page instead of a SAML response; XML entity/prologue issues.

Related errors


AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10). Data as JSON: /api/errors/d73ba0e6e0c6a105. Report an issue: GitHub.