boto3 s3 Object expiration "MalformedXML" error

Question:

I’m trying to set the lifecycle configuration of a subdirectory in Amazon S3 bucket by using boto3 put_bucket_lifecycle_configuration. I used this code from aws documentation as referece:

lifecycle_config_settings = {
    'Rules': [
        {'ID': 'S3 Glacier Transition Rule',
         'Filter': {'Prefix': ''},
         'Status': 'Enabled',
         'Transitions': [
             {'Days': 0,
              'StorageClass': 'GLACIER'}
         ]}
    ]}

I removed Transitions and added Expiration, to better fit my purpouses. Here is my code:

myDirectory = 'table-data/'

lifecycle_config_settings = {
    'Rules': [{
        'ID': 'My rule',
        'Expiration': {
            'Days': 30,
            'ExpiredObjectDeleteMarker': True
        },
        'Filter': {'Prefix': myDirectory},
        'Status': 'Enabled'
     }
]}

s3 = boto3.client('s3')
s3.put_bucket_lifecycle_configuration(
    Bucket=myBucket,
    LifecycleConfiguration=lifecycle_config_settings
)

The error I’m receiving is:

An error occurred (MalformedXML) when calling the PutBucketLifecycleConfiguration operation: The XML you provided was not well-formed or did not validate against our published schema

What could be causing this error?

Asked By: samlima

||

Answers:

I followed @Michael-sqlbot suggestion and found the reason it wasn’t working.

The problem in this settings is in 'ExpiredObjectDeleteMarker': True that is inside Expiration key. In boto3 documentation there is an observation about it.

'ExpiredObjectDeleteMarker' cannot be specified with Days or Date in a Lifecycle Expiration Policy.

Fixing it, the settings will be:

lifecycle_config_settings = {
    'Rules': [{
        'ID': 'My rule',
        'Expiration': {
            'Days': 30
        },
        'Filter': {'Prefix': myDirectory},
        'Status': 'Enabled'
     }
]}
Answered By: samlima

Just to add to SamLima’s answer, it’s really not possible to use both in one rule. In my case, I created two rules and I’ll leave the code here to help those who need to solve this case the same way I do:

response = client.put_bucket_lifecycle_configuration(
    Bucket=bucket_name,
    LifecycleConfiguration={
        'Rules': [
            {
                "ID": "Rule 1",
                "Expiration": {
                    "Days": 100,
                },
                "NoncurrentVersionExpiration": {
                    "NoncurrentDays": 100
                },
                "Filter": {
                    "Prefix": "Prefix_1"
                },
                "Status": 'Enabled'
            },
            {
                "ID": "Rule 2",
                "Expiration": {
                    "ExpiredObjectDeleteMarker": True
                },
                "AbortIncompleteMultipartUpload": {
                    "DaysAfterInitiation": 1
                },
                "Filter": {
                    "Prefix": "Prefix_1"
                },
                "Status": 'Enabled'
            }
        ]
    }
)
Answered By: Lazaro Jr.