spring-projects/spring-security · error · IllegalArgumentException

metadataResolver must be an IterableMetadataSource or have a

Error message

metadataResolver must be an IterableMetadataSource or have a RoleMetadataIndex

What it means

BaseOpenSamlAssertingPartyMetadataRepository's constructor requires the supplied resolver adapter to either expose a RoleMetadataIndex (allowing role-based entity lookups) or be an IterableMetadataSource (allowing plain iteration). Neither being true makes the repository unable to enumerate IDP EntityDescriptors, so it rejects the configuration with this IllegalArgumentException.

Source

Thrown at saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/registration/BaseOpenSamlAssertingPartyMetadataRepository.java:68

	 * Construct an {@link BaseOpenSamlAssertingPartyMetadataRepository} using the
	 * provided {@link MetadataResolver}.
	 *
	 * <p>
	 * The {@link MetadataResolver} should either be of type
	 * {@link IterableMetadataSource} or it should have a {@link RoleMetadataIndex}
	 * configured.
	 * @param metadataResolver the {@link MetadataResolver} to use
	 */
	BaseOpenSamlAssertingPartyMetadataRepository(MetadataResolverAdapter metadataResolver) {
		Assert.notNull(metadataResolver, "metadataResolver cannot be null");
		if (isRoleIndexed(metadataResolver.metadataResolver)) {
			this.descriptors = this::allIndexedEntities;
		}
		else if (metadataResolver.metadataResolver instanceof IterableMetadataSource source) {
			this.descriptors = source::iterator;
		}
		else {
			throw new IllegalArgumentException(
					"metadataResolver must be an IterableMetadataSource or have a RoleMetadataIndex");
		}
		this.metadataResolver = metadataResolver;
	}

	private static boolean isRoleIndexed(MetadataResolver resolver) {
		if (!(resolver instanceof AbstractBatchMetadataResolver batch)) {
			return false;
		}
		for (MetadataIndex index : batch.getIndexes()) {
			if (index instanceof RoleMetadataIndex) {
				return true;
			}
		}
		return false;
	}

	private Iterator<EntityDescriptor> allIndexedEntities() {

View on GitHub (pinned to 96852e8860)

Solutions

  1. Add a RoleMetadataIndex to your resolver: metadataResolver.setIndexes(Set.of(new RoleMetadataIndex())) before initialize()
  2. Or implement/wrap the resolver as an IterableMetadataSource that can iterate all entities
  3. Use one of Spring Security's provided adapters (e.g. ResourceBackedMetadataResolver via initialize()) instead of a custom one
  4. Review the repository Javadoc/constructor for the accepted resolver shapes

Example fix

// before
var adapter = new MetadataResolverAdapter(myPlainResolver) {};
// after
myPlainResolver.setIndexes(Set.of(new RoleMetadataIndex()));
myPlainResolver.initialize();
var adapter = new MetadataResolverAdapter(myPlainResolver) {};
Defensive patterns

Strategy: validation

Validate before calling

void requireUsableResolver(MetadataResolver r) {
    boolean roleIndexed = r != null && r.getIndexes() != null
        && r.getIndexes().stream().anyMatch(RoleMetadataIndex.class::isInstance);
    boolean iterable = r instanceof IterableMetadataSource;
    if (!roleIndexed && !iterable) {
        throw new IllegalArgumentException("resolver needs RoleMetadataIndex or IterableMetadataSource");
    }
}

Try / catch

try {
    var repo = new ResourceBackedAssertingPartyMetadataRepository(resource);
} catch (Saml2Exception | IllegalArgumentException ex) {
    logger.error("Bad metadata resolver configuration: {}", ex.getMessage(), ex);
    throw ex;
}

Prevention

When it happens

Trigger: Constructing BaseOpenSamlAssertingPartyMetadataRepository (or a subclass like the file-system/JDBC variants) with a MetadataResolverAdapter whose metadataResolver is not role-indexed and does not implement IterableMetadataSource.

Common situations: Passing a custom OpenSAML MetadataResolver (e.g. a plain FilesystemMetadataResolver or DynamicEntityMetadataResolver) into a resource-backed repository without wrapping it or adding a RoleMetadataIndex; upgrading Spring Security where repository construction API changed; hand-rolling the adapter for tests.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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