{"record":{"id":"2696d3bf709d2d0b","repo":"apereo/cas","slug":"multiple-s3-objects-where-found-in-bucket","errorCode":null,"errorMessage":"Multiple S3 objects where found in bucket ","messagePattern":"Multiple S3 objects where found in bucket ","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"support/cas-server-support-saml-idp-metadata-aws-s3/src/main/java/org/apereo/cas/support/saml/idp/metadata/AmazonS3SamlIdPMetadataLocator.java","lineNumber":66,"sourceCode":"            LOGGER.debug(\"S3 bucket [{}] does not exist\", bucketToUse);\n            return null;\n        }\n\n        val result = s3Client.listObjectsV2(ListObjectsV2Request.builder().bucket(bucketToUse).build());\n        val objects = result.contents();\n        LOGGER.debug(\"Located [{}] S3 object(s) from bucket [{}]\", objects.size(), bucketToUse);\n\n        if (objects.isEmpty()) {\n            return null;\n        }\n        if (objects.size() > 1) {\n            LOGGER.warn(\"Located [{}] S3 object(s) from bucket [{}]\", objects.size(), bucketToUse);\n            objects.forEach(obj -> {\n                LOGGER.debug(\"Deleting object [{}] from bucket [{}]\", obj.key(), bucketToUse);\n                val deleteRequest = DeleteObjectRequest.builder().bucket(bucketToUse).key(obj.key()).build();\n                s3Client.deleteObject(deleteRequest);\n            });\n            throw new IllegalArgumentException(\"Multiple S3 objects where found in bucket \" + bucketToUse);\n        }\n\n        val firstMetadataObject = objects.getFirst();\n        LOGGER.debug(\"Fetching object [{}] from bucket [{}]\", firstMetadataObject.key(), bucketToUse);\n        val metadataEntry = s3Client.getObject(GetObjectRequest.builder().bucket(bucketToUse).key(firstMetadataObject.key()).build());\n        return AmazonS3SamlIdPMetadataUtils.readMetadataDocumentFromBucket(metadataEntry, bucketToUse);\n    }\n}\n\n","sourceCodeStart":48,"sourceCodeEnd":76,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-saml-idp-metadata-aws-s3/src/main/java/org/apereo/cas/support/saml/idp/metadata/AmazonS3SamlIdPMetadataLocator.java#L48-L76","documentation":"AmazonS3SamlIdPMetadataLocator.fetchInternal() lists objects in the configured S3 bucket expecting exactly one metadata object. If more than one object is found it logs a warning, deletes all located objects, and throws IllegalArgumentException that multiple S3 objects were found in the bucket.","triggerScenarios":"fetchInternal() (public) calls listObjectsV2 on bucketToUse and the result contains 2+ keys — e.g. metadata written multiple times without cleanup, or the bucket is shared with other content.","commonSituations":"Reusing one bucket for multiple IdP services/versions; a failed previous upload left stale objects; misconfigured bucket/prefix so unrelated objects are matched; concurrent writers.","solutions":["Empty the bucket (or the configured key prefix) so exactly one metadata object remains, then regenerate the IdP metadata once.","Give each registered service/IdP its own bucket or prefix so locator queries cannot match multiple objects.","Audit what wrote the extra objects (repeated sso/idp metadata generation) and disable duplicate writers.","Re-run metadata generation after cleanup; note this locator deletes the conflicting objects before throwing."],"exampleFix":"// before (shared bucket with leftovers)\ncas.authn.samlIdp.metadata.amazon-s3.bucket-name=cas-saml-metadata   // contains idp-metadata.xml, idp-metadata(1).xml\n\n// after\naws s3 rm s3://cas-saml-metadata --exclude \"*\" --include \"*.xml\"\n# then regenerate metadata once; or dedicate bucket per service\ncas.authn.samlIdp.metadata.amazon-s3.bucket-name=cas-saml-metadata-sp1","handlingStrategy":"validation","validationCode":"// before configuring the S3 locator, verify bucket holds exactly one metadata object\nvar listing = s3.listObjectsV2(ListObjectsV2Request.builder().bucket(bucket).build());\nif (listing.contents().size() != 1)\n    throw new IllegalStateException(\"Bucket \" + bucket + \" must contain exactly 1 object, has \" + listing.contents().size());","typeGuard":null,"tryCatchPattern":"try {\n    doc = locator.fetch();\n} catch (IllegalArgumentException e) {\n    logger.error(\"S3 bucket cleanup required: {}\", e.getMessage());\n}","preventionTips":["Dedicate one bucket or key prefix per metadata artifact.","Enable S3 versioning instead of accumulating sibling objects.","Monitor the bucket object count and alert when it exceeds one."],"tags":["saml","idp","aws","s3","metadata"],"backgroundTag":"invalid-state-transition","analyzedSha":"e7288fc434b4f4505b8452e1a57e8fb3111bb863","analyzedAt":"2026-09-08T15:39:16.015Z","contentChangedAt":"2026-09-08T15:39:16.015Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}