spring-projects/spring-security · error · Saml2Exception

Unable to resolve Builder for

Error message

Unable to resolve Builder for 

What it means

OpenSaml5Template.build() looks up an OpenSAML XMLObjectBuilder for the given element QName via the global XMLObjectProviderRegistry. OpenSAML throws this Saml2Exception when no builder has been registered for that element name, meaning the corresponding OpenSAML module's ObjectProvider init was never run or the QName is not a recognized SAML element. Spring Security cannot construct the requested XMLObject, so it fails fast instead of returning null.

Source

Thrown at saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/web/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. Call OpenSamlInitializationService.initialize() (or ensure the OpenSAML InitializationService runs) before using OpenSaml5Template so all default object providers are registered.
  2. Verify the QName's namespace URI and local part exactly match a SAML element (e.g. Assertion.DEFAULT_ELEMENT_NAME) rather than a hand-built QName.
  3. Check for conflicting OpenSAML versions on the classpath (only opensaml-core/opensaml-xmlsec etc. v5 should be present) and re-run the provider registration.
  4. If using a custom element, register its builder via the XMLObjectProviderRegistry (XMLObjectProviderRegistrySupport.getRegistry().registerObjectProvider(...)).

Example fix

// before
QName name = new QName("Assertion"); // no namespace -> unresolvable
Assertion a = template.build(name);

// after
OpenSamlInitializationService.initialize();
Assertion a = template.build(Assertion.DEFAULT_ELEMENT_NAME); // canonical QName with SAML namespace
Defensive patterns

Strategy: validation

Validate before calling

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

Try / catch

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

Prevention

When it happens

Trigger: Calling OpenSaml5Template.build(QName) with an element name for which XMLObjectProviderRegistrySupport.getBuilderFactory().getBuilder(elementName) returns null — e.g. a QName whose namespace/qualified name does not match any registered SAML object provider.

Common situations: Using a custom or misspelled QName; calling build() before OpenSAML's InitializationService/global registry was initialized (typically done by OpenSamlInitializationService.initialize()); mixing OpenSAML 4 and 5 jars on the classpath so providers register under a different registry; using an element from a SAML profile (e.g. ECP, metadata extensions) whose module is not initialized.

Related errors


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