spring-projects/spring-security · error · Saml2Exception
Saml2Exception wrapping MarshallingException while re-marsha
Error message
Saml2Exception wrapping MarshallingException while re-marshalling response after decryption
What it means
After decrypting embedded encrypted assertions, decryptResponse re-marshalls the Response via XMLObjectSupport.marshall so decrypted ID attributes are re-established at the DOM level; a MarshallingException is wrapped in Saml2Exception. Marshalling converts the OpenSAML object model back to a DOM Element, and it fails if the object tree is inconsistent or unassignable to XML.
Source
Thrown at saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/web/OpenSaml5Template.java:532
}
count++;
}
catch (DecryptionException ex) {
throw new Saml2Exception(ex);
}
}
response.getAssertions().addAll(decrypteds);
// Re-marshall the response so that any ID attributes within the decrypted
// Assertions
// will have their ID-ness re-established at the DOM level.
if (!decrypteds.isEmpty()) {
try {
XMLObjectSupport.marshall(response);
}
catch (final MarshallingException ex) {
throw new Saml2Exception(ex);
}
}
}
private void decryptAssertion(Assertion assertion) {
for (AttributeStatement statement : assertion.getAttributeStatements()) {
decryptAttributes(statement);
}
decryptSubject(assertion.getSubject());
if (assertion.getConditions() != null) {
for (Condition c : assertion.getConditions().getConditions()) {
if (!(c instanceof DelegationRestrictionType delegation)) {
continue;
}
for (Delegate d : delegation.getDelegates()) {
if (d.getEncryptedID() != null) {
try {
NameID decrypted = (NameID) this.decrypter.decrypt(d.getEncryptedID());View on GitHub (pinned to 96852e8860)
Solutions
- Ensure the Response is parsed and processed single-threaded and not already marshalled/unmarshalled in a conflicting way
- Rebuild or re-parse the Response from its XML source if its object model was mutated externally
- Update OpenSAML/spring-security-saml2-service-provider to a version with known marshalling fixes
- Catch Saml2Exception and log the wrapped MarshallingException stack for the failing element
Example fix
// before response.getAssertions().add(customMutableAssertion); // mutated externally XMLObjectSupport.marshall(response); // after response = parseResponse(xmlBytes); // fresh object model before decryption
Defensive patterns
Strategy: try-catch
Try / catch
try { XMLObjectSupport.marshall(response); } catch (Saml2Exception e) { log.error("Re-marshal after decrypt failed", e.getCause()); } Prevention
- Do not mutate the Response object model outside the template's decrypt flow
- Never share a parsed Response across threads
- Pin OpenSAML/spring-security versions together and upgrade in step
When it happens
Trigger: decryptResponse() with at least one successfully decrypted assertion calls XMLObjectSupport.marshall(response); this throws MarshallingException if the response's XMLObject/DOM state is inconsistent (e.g. already-owned DOM conflicts, missing namespace/schema info after mutation).
Common situations: Custom code mutating the response between parse and decrypt; OpenSAML version upgrades changing marshall behavior; concurrent reuse of a single Response object across threads causing DOM ownership conflicts.
Related errors
- Spring Security does not support OpenSAML {Version.getVersio
- Spring Security does not support OpenSAML {Version.getVersio
- Saml2Exception wrapping MarshallingException during serializ
- Unable to resolve Builder for
- Unsupported element of type
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/60611530ca64ad34.
Report an issue: GitHub.