S3 Error: “An error occurred (AccessDenied) when calling the PutObject operation: Access Denied”

 

S3 Error: “An error occurred (AccessDenied) when calling the PutObject operation: Access Denied”

Fix the exact permissions, policy, encryption, and ownership issues that cause S3 uploads to fail with PutObject AccessDenied errors in modern AWS environments

#AWS #AmazonS3 #CloudComputing #DevOps




Problem

You are attempting to upload an object to an Amazon S3 bucket using the AWS CLI, SDK, application code, automation pipeline, or another AWS service, and the upload fails with the following error:

An error occurred (AccessDenied) when calling the PutObject operation: Access Denied

This error commonly appears during:

  • aws s3 cp
  • aws s3 sync
  • SDK uploads
  • Lambda uploads
  • CI/CD artifact pushes
  • Cross-account uploads
  • Automated backups or exports

At first glance, the error looks simple.

In practice, modern S3 uploads pass through multiple layers of authorization and security controls, and any one of them can block the request.


Clarifying the Issue

This error means the caller successfully reached S3, but S3 rejected the upload attempt.

The request was authenticated.

The upload operation itself was denied.

In modern AWS environments, the most common causes include:

  • Missing s3:PutObject
  • Bucket policy denies
  • KMS permission failures
  • Object Ownership conflicts
  • Explicit denies from SCPs
  • Cross-account upload restrictions
  • Public Access Block interactions

It is also important to understand the difference between:

  • implicit deny
  • explicit deny

AWS denies requests by default unless an allow exists.

That is an implicit deny.

An explicit deny is a policy statement that directly blocks the action, and explicit denies always override allows.

This is no longer just an IAM issue.

Modern S3 authorization is a layered system.


Why It Matters

A failed PutObject operation can stop:

  • application uploads
  • deployment pipelines
  • log ingestion
  • backups
  • media processing
  • Lambda workflows
  • cross-region automation

In production environments, this error often cascades into secondary failures that appear unrelated until the upload path is investigated.


Key Terms

  • s3:PutObject Permission required to upload objects to S3

  • Bucket Policy Resource-based permissions attached to the bucket

  • Explicit Deny A deny rule that overrides allows

  • Implicit Deny Default AWS behavior when no allow exists

  • SSE-KMS Server-side encryption using AWS KMS

  • Object Ownership S3 ownership model controlling ACL behavior

  • SCP (Service Control Policy) Organization-level policy control in AWS Organizations


Steps at a Glance

  1. Verify the caller identity
  2. Confirm s3:PutObject permissions
  3. Check the bucket policy for denies
  4. Verify KMS permissions if encryption is enabled
  5. Check Object Ownership settings
  6. Test the upload again

Detailed Steps

Step 1. Verify the Caller Identity

First confirm which IAM identity is making the request.

Run:

aws sts get-caller-identity

This immediately tells you:

  • IAM user
  • assumed role
  • account ID

Many AccessDenied investigations fail because engineers troubleshoot the wrong identity.

This is especially common in:

  • CI/CD systems
  • Lambda execution roles
  • local CLI profiles
  • temporary session credentials

Step 2. Confirm s3:PutObject Permissions

The caller must have permission to upload objects.

Example IAM policy:

{
  "Effect": "Allow",
  "Action": "s3:PutObject",
  "Resource": "arn:aws:s3:::my-bucket/*"
}

A common mistake is using:

"Resource": "arn:aws:s3:::my-bucket"

instead of:

"Resource": "arn:aws:s3:::my-bucket/*"

This matters because:

  • arn:aws:s3:::my-bucket refers to the bucket itself
  • arn:aws:s3:::my-bucket/* refers to the objects inside the bucket

PutObject applies to objects, not the bucket resource.

Common problems include:

  • Wrong bucket ARN
  • Missing /*
  • Policy attached to the wrong role
  • Session policy restrictions

If uploading into a prefix, confirm the policy allows that path.


Step 3. Check the Bucket Policy for Denies

Even if IAM allows the upload, the bucket policy may block it.

Look for:

  • explicit denies
  • account restrictions
  • source IP conditions
  • VPC endpoint conditions
  • encryption enforcement

Example deny pattern:

{
  "Effect": "Deny",
  "Principal": "*",
  "Action": "s3:PutObject",
  "Resource": "arn:aws:s3:::my-bucket/*"
}

An explicit deny always overrides an allow.

Also remember: if neither the IAM policy nor the bucket policy explicitly allows the request, AWS denies the operation by default.

Review bucket policy conditions carefully for logic that unintentionally matches your request.


Step 4. Verify KMS Permissions if Encryption Is Enabled

If the bucket enforces SSE-KMS encryption, the caller also needs KMS permissions.

Common required permissions include:

  • kms:Encrypt
  • kms:GenerateDataKey

However, IAM permissions alone may not be enough.

The KMS key policy itself must also allow the caller or account to use the key.

This is one of the most common hidden causes of PutObject AccessDenied failures.

Check:

  • IAM permissions
  • KMS key policy
  • bucket encryption settings

in combination.


Step 5. Check Object Ownership Settings

Many older workflows relied on ACL behavior that no longer functions the same way in modern S3 environments.

Review:

  • Bucket owner enforced
  • Bucket owner preferred
  • ACL usage
  • cross-account ownership assumptions

Modern S3 deployments increasingly use:

  • Object Ownership
  • ACL-disabled configurations

Cross-account upload workflows are especially sensitive to these settings.

Also verify whether AWS Organizations SCPs are blocking S3 actions globally.

An SCP explicit deny can override otherwise correct IAM and bucket permissions.


Step 6. Test the Upload Again

After corrections, retry the upload:

aws s3 cp test.txt s3://my-bucket/

If the upload succeeds, confirm:

  • encryption behavior
  • object ownership
  • downstream automation
  • application integration

Do not stop at “upload worked once.”

Validate the entire workflow.


Pro Tips

  • AccessDenied is often a symptom, not the root cause
  • KMS failures frequently masquerade as S3 permission failures
  • Cross-account uploads are especially sensitive to Object Ownership changes
  • SCP explicit denies can silently override otherwise correct IAM permissions
  • Always verify the actual runtime role, especially in Lambda and CI/CD systems
  • Missing /* in S3 object ARNs remains one of the most common policy mistakes

Conclusion

The error:

An error occurred (AccessDenied) when calling the PutObject operation: Access Denied

usually means the upload request successfully reached S3, but one of the surrounding authorization layers rejected the operation.

In modern AWS environments, successful uploads depend on aligned:

  • IAM permissions
  • bucket policies
  • encryption permissions
  • Object Ownership settings
  • KMS key policies
  • organizational controls

Systematically checking each layer is the fastest path to resolution.


Aaron Rose is a software engineer and technology writer at tech-reader.blog

Catch up on the latest explainer videos, podcasts, and industry discussions below.


Popular posts from this blog

Insight: The Great Minimal OS Showdown—DietPi vs Raspberry Pi OS Lite

Running AI Models on Raspberry Pi 5 (8GB RAM): What Works and What Doesn't

Raspberry Pi Connect vs. RealVNC: A Comprehensive Comparison