{"record":{"id":"9f621134d352981c","repo":"spring-projects/spring-security","slug":"metadataresolver-must-be-an-iterablemetadatasource","errorCode":null,"errorMessage":"metadataResolver must be an IterableMetadataSource or have a RoleMetadataIndex","messagePattern":"metadataResolver must be an IterableMetadataSource or have a RoleMetadataIndex","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/registration/BaseOpenSamlAssertingPartyMetadataRepository.java","lineNumber":68,"sourceCode":"\t * Construct an {@link BaseOpenSamlAssertingPartyMetadataRepository} using the\n\t * provided {@link MetadataResolver}.\n\t *\n\t * <p>\n\t * The {@link MetadataResolver} should either be of type\n\t * {@link IterableMetadataSource} or it should have a {@link RoleMetadataIndex}\n\t * configured.\n\t * @param metadataResolver the {@link MetadataResolver} to use\n\t */\n\tBaseOpenSamlAssertingPartyMetadataRepository(MetadataResolverAdapter metadataResolver) {\n\t\tAssert.notNull(metadataResolver, \"metadataResolver cannot be null\");\n\t\tif (isRoleIndexed(metadataResolver.metadataResolver)) {\n\t\t\tthis.descriptors = this::allIndexedEntities;\n\t\t}\n\t\telse if (metadataResolver.metadataResolver instanceof IterableMetadataSource source) {\n\t\t\tthis.descriptors = source::iterator;\n\t\t}\n\t\telse {\n\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\"metadataResolver must be an IterableMetadataSource or have a RoleMetadataIndex\");\n\t\t}\n\t\tthis.metadataResolver = metadataResolver;\n\t}\n\n\tprivate static boolean isRoleIndexed(MetadataResolver resolver) {\n\t\tif (!(resolver instanceof AbstractBatchMetadataResolver batch)) {\n\t\t\treturn false;\n\t\t}\n\t\tfor (MetadataIndex index : batch.getIndexes()) {\n\t\t\tif (index instanceof RoleMetadataIndex) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate Iterator<EntityDescriptor> allIndexedEntities() {","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/registration/BaseOpenSamlAssertingPartyMetadataRepository.java#L50-L86","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Add a RoleMetadataIndex to your resolver: metadataResolver.setIndexes(Set.of(new RoleMetadataIndex())) before initialize()","Or implement/wrap the resolver as an IterableMetadataSource that can iterate all entities","Use one of Spring Security's provided adapters (e.g. ResourceBackedMetadataResolver via initialize()) instead of a custom one","Review the repository Javadoc/constructor for the accepted resolver shapes"],"exampleFix":"// before\nvar adapter = new MetadataResolverAdapter(myPlainResolver) {};\n// after\nmyPlainResolver.setIndexes(Set.of(new RoleMetadataIndex()));\nmyPlainResolver.initialize();\nvar adapter = new MetadataResolverAdapter(myPlainResolver) {};","handlingStrategy":"validation","validationCode":"void requireUsableResolver(MetadataResolver r) {\n    boolean roleIndexed = r != null && r.getIndexes() != null\n        && r.getIndexes().stream().anyMatch(RoleMetadataIndex.class::isInstance);\n    boolean iterable = r instanceof IterableMetadataSource;\n    if (!roleIndexed && !iterable) {\n        throw new IllegalArgumentException(\"resolver needs RoleMetadataIndex or IterableMetadataSource\");\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    var repo = new ResourceBackedAssertingPartyMetadataRepository(resource);\n} catch (Saml2Exception | IllegalArgumentException ex) {\n    logger.error(\"Bad metadata resolver configuration: {}\", ex.getMessage(), ex);\n    throw ex;\n}","preventionTips":["Always set Set.of(new RoleMetadataIndex()) on custom resolvers passed to these repositories","Prefer Spring Security's own ResourceBackedMetadataResolver/initialize() helper over raw OpenSAML resolvers","Unit-test repository construction with your resolver at startup (fail fast)"],"tags":["saml","metadata","configuration","illegal-argument"],"backgroundTag":"invalid-argument-value","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}