spring-projects/spring-security · error · Saml2Exception

Unable to resolve Builder for

Error message

Unable to resolve Builder for 

What it means

Identical to error 580 but in the logout package's OpenSaml5Template: build() throws this Saml2Exception when OpenSAML's XMLObjectBuilderFactory has no builder registered for the given QName, so the requested SAML element cannot be constructed.

Source

Thrown at saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/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. Initialize OpenSAML via OpenSamlInitializationService.initialize() before calling build().
  2. Use canonical constants like LogoutRequest.DEFAULT_ELEMENT_NAME rather than manually constructed QNames.
  3. Remove conflicting OpenSAML versions from the classpath and confirm providers load at startup.
  4. For custom elements, register an XMLObjectBuilder in the XMLObjectProviderRegistry.

Example fix

// before
QName q = new QName("LogoutRequest");
LogoutRequest req = template.build(q);

// after
OpenSamlInitializationService.initialize();
LogoutRequest req = template.build(LogoutRequest.DEFAULT_ELEMENT_NAME);
Defensive patterns

Strategy: validation

Validate before calling

OpenSamlInitializationService.initialize();
if (XMLObjectProviderRegistrySupport.getBuilderFactory().getBuilder(elementName) == null) {
    throw new IllegalStateException("No OpenSAML builder for " + elementName);
}

Try / catch

try { T obj = template.build(elementName); } catch (Saml2Exception ex) { log.error("Logout template cannot build {}", elementName, ex); throw ex; }

Prevention

When it happens

Trigger: Calling the logout OpenSaml5Template.build(QName) with an element name for which getBuilderFactory().getBuilder(elementName) returns null (unregistered/unknown element).

Common situations: Building LogoutRequest/LogoutResponse with a hand-crafted QName instead of the *.DEFAULT_ELEMENT_NAME constants; OpenSAML registry not initialized; duplicate OpenSAML 4/5 jars; using extension elements whose providers were never registered.

Related errors


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