I set up S3 Cross-Region Replication to backup data from a bucket in us-east-1 to a bucket in eu-west-1. The replication rule looked correct, but days later, objects in the destination bucket were missing. I checked the replication status and saw “PENDING” and “FAILED” states, which sent me down a rabbit hole of IAM roles, versioning settings, and replication rule filters. In this post, I’ll walk through exactly what causes this and how to fix it.

The Problem

You’ve configured S3 Cross-Region Replication (CRR) but new objects uploaded to the source bucket don’t appear in the destination. In the S3 console, the replication status shows PENDING or FAILED, or objects simply don’t appear with no status recorded.

Error Type Description
Replication Status: PENDING The object is queued for replication but hasn’t been replicated yet.
Replication Status: FAILED Replication attempted but failed, usually due to permissions or configuration.
No Status Object exists in source but no replication status appears (configuration issue).

Why Does This Happen?

  • Replication only applies to new objects — CRR is prospective, not retroactive. Objects uploaded before CRR was enabled are not replicated. Existing objects must be replicated manually using S3 Batch Operations.
  • IAM role lacks permissions — The replication role must have s3:GetObject on the source bucket and s3:PutObject on the destination. Without both, replication fails silently.
  • Destination bucket versioning not enabledS3 CRR requires versioning on both the source and destination buckets. If the destination lacks versioning, replication fails.
  • Source bucket versioning not enabled — CRR cannot function without versioning on the source bucket. The replication configuration itself requires the source to be versioned.
  • Replication rule filter excludes the object — The replication rule uses a prefix or tag filter that doesn’t match your objects. Objects outside the filter scope are silently ignored.

The Fix

Step 1: Enable Versioning on Both Buckets

Both the source and destination buckets must have versioning enabled:

# Enable versioning on source bucket
aws s3api put-bucket-versioning \
  --bucket source-bucket \
  --versioning-configuration Status=Enabled

# Enable versioning on destination bucket
aws s3api put-bucket-versioning \
  --bucket destination-bucket \
  --versioning-configuration Status=Enabled

# Verify versioning is enabled
aws s3api get-bucket-versioning --bucket source-bucket

Step 2: Create or Update the IAM Role

Create an IAM role with the required permissions:

cat > trust-policy.json <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "s3.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
EOF

aws iam create-role \
  --role-name s3-replication-role \
  --assume-role-policy-document file://trust-policy.json

cat > role-policy.json <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetReplicationConfiguration",
        "s3:ListBucket"
      ],
      "Resource": "arn:aws:s3:::source-bucket"
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObjectVersionForReplication",
        "s3:GetObjectVersionAcl"
      ],
      "Resource": "arn:aws:s3:::source-bucket/*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:ReplicateObject",
        "s3:ReplicateDelete"
      ],
      "Resource": "arn:aws:s3:::destination-bucket/*"
    }
  ]
}
EOF

aws iam put-role-policy \
  --role-name s3-replication-role \
  --policy-name s3-replication-policy \
  --policy-document file://role-policy.json

Step 3: Configure Replication Rule

Create the replication configuration:

cat > replication-config.json <<EOF
{
  "Role": "arn:aws:iam::123456789012:role/s3-replication-role",
  "Rules": [
    {
      "ID": "replicate-all",
      "Status": "Enabled",
      "Priority": 1,
      "Filter": {
        "Prefix": ""
      },
      "Destination": {
        "Bucket": "arn:aws:s3:::destination-bucket",
        "ReplicationTime": {
          "Status": "Enabled",
          "Time": {
            "Minutes": 15
          }
        }
      }
    }
  ]
}
EOF

aws s3api put-bucket-replication \
  --bucket source-bucket \
  --replication-configuration file://replication-config.json

Step 4: Verify Replication Configuration

Check the replication rule is applied:

aws s3api get-bucket-replication --bucket source-bucket

Step 5: Replicate Existing Objects (Optional)

If you need to replicate objects uploaded before CRR was enabled:

# List objects and their replication status
aws s3api head-object \
  --bucket source-bucket \
  --key your-object-key

# Use S3 Batch Operations to replicate all existing objects
# This requires creating a Batch Operations job through the console or SDK

How to Run This

  1. Replace source-bucket and destination-bucket with your actual bucket names
  2. Replace 123456789012 with your AWS account ID
  3. Run commands in order: enable versioning first, then create the IAM role, then apply the replication configuration
  4. Upload a test object to the source bucket and check the destination within 15 minutes
  5. Verify replication status in the S3 console or using head-object

Is This Safe?

Replication is safe and recommended for disaster recovery. The IAM role is scoped to the source and destination buckets, preventing access to other resources. For production, use Replication Time Control (RTC) to guarantee 15-minute replication with compliance reports.

Key Takeaway

S3 Cross-Region Replication requires versioning on both buckets, a properly configured IAM role, and a matching replication rule filter. Test with a new object immediately after setup to confirm the configuration works.


Have questions or ran into a different S3 issue? Connect with me on LinkedIn or X.