spring-projects/spring-security · error · Saml2Exception

Unable to resolve Builder for " + elementName

Error message

Unable to resolve Builder for " + elementName

What it means

OpenSaml5Template.build(QName) asks the OpenSAML XMLObjectBuilderFactory for a builder registered for the given element QName. If OpenSAML has no builder for that element name (unknown element, wrong namespace, or uninitialized registries), it throws Saml2Exception('Unable to resolve Builder for <elementName>').

Source

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

import org.springframework.security.saml2.core.Saml2ParameterNames;
import org.springframework.security.saml2.core.Saml2X509Credential;
import org.springframework.util.Assert;
import org.springframework.web.util.UriComponentsBuilder;
import org.springframework.web.util.UriUtils;

/**
 * For internal use only. Subject to breaking changes at any time.
 */
@NullMarked
final class OpenSaml5Template implements OpenSamlOperations {

	private static final Log logger = LogFactory.getLog(OpenSaml5Template.class);

	@Override
	public <T extends XMLObject> T build(QName elementName) {
		XMLObjectBuilder<?> builder = XMLObjectProviderRegistrySupport.getBuilderFactory().getBuilder(elementName);
		if (builder == null) {
			throw new Saml2Exception("Unable to resolve Builder for " + elementName);
		}
		return (T) builder.buildObject(elementName);
	}

	@Override
	public <T extends XMLObject> T deserialize(String serialized) {
		return deserialize(new ByteArrayInputStream(serialized.getBytes(StandardCharsets.UTF_8)));
	}

	@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);

View on GitHub (pinned to 96852e8860)

Solutions

  1. Use the constants from net.shibboleth.opensaml or org.opensaml.saml (e.g. LogoutRequest.DEFAULT_ELEMENT_NAME) instead of hand-built QNames so namespace and element name match exactly.
  2. Call OpenSamlInitializationService.initialize() at startup so default builders are registered.
  3. For custom extension elements, register an XMLObjectBuilder for their QName via XMLObjectProviderRegistrySupport / an ObjectProvider.
  4. Print the failing QName and compare its namespaceURI/localPart against OpenSAML's registered element names.

Example fix

// before
QName qname = new QName("logout", "LogoutRequest");
LogoutRequest req = template.build(qname);
// after
LogoutRequest req = template.build(LogoutRequest.DEFAULT_ELEMENT_NAME);
Defensive patterns

Strategy: validation

Validate before calling

XMLObjectBuilder<?> b = XMLObjectProviderRegistrySupport.getBuilderFactory().getBuilder(elementName);
if (b == null) {
    throw new IllegalArgumentException("No OpenSAML builder registered for " + elementName);
}

Try / catch

try {
    T obj = template.build(elementName);
} catch (Saml2Exception ex) {
    throw new IllegalStateException("OpenSAML builder missing — check initialization and QName", ex);
}

Prevention

When it happens

Trigger: Calling template.build(qName) with a QName not registered in OpenSAML's builder factory — custom extension elements, typo'd namespace URIs, or building SAML elements before OpenSAML bootstrap has registered defaults.

Common situations: Constructing LogoutRequest/AttributeQuery or vendor-extension elements with a hand-built QName whose namespace URI or prefix spelling is wrong; forgetting OpenSamlInitializationService.initialize() in a custom setup; mixing OpenSAML 4-era element constants with OpenSAML 5 namespaces.

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 spring-projects/spring-security@96852e8860 (2026-09-10). Data as JSON: /api/errors/dde2698a269678d1. Report an issue: GitHub.