S3 Inventory delivery fails with 'internal error' when the destination bucket's default encryption uses a bare KMS alias instead of a fully qualified ARN.
S3 Inventory reports never deliver and the console shows only a generic "internal error." That message is a catch-all. This article documents one specific, easily-missed cause, where every permission you'd check looks correct. However, the destination bucket's SSE-KMS default encryption references the KMS key by a bare alias / key ID instead of a fully qualified key ARN.
Symptom
S3 Inventory reports never arrive. This most often shows up on a newly configured inventory, or after the destination bucket's default encryption was set or changed to reference the key by a bare alias: the scheduled delivery fails, and so does every one after it. (It is not a case of a working inventory suddenly stopping.) On the source bucket's Management → Inventory configurations view, the most recent run shows a failure and the console surfaces a generic "internal error" with no cause and no actionable detail. Nothing looked wrong at setup: the inventory configuration was accepted without error when you created it, and the destination bucket, its policy, and the KMS key all appear correctly configured.
Why this is hard to diagnose
This error gives no direction, and every obvious suspect reads as properly configured. All of the following were verified correct before the actual cause was found:
- ✅ Destination bucket policy grants
s3:PutObject/s3:PutObject*to thes3.amazonaws.comservice principal. - ✅ KMS key policy grants
kms:GenerateDataKey*(andkms:Encrypt) tos3.amazonaws.com. - ✅ Object Ownership / ACLs on the destination support the delivery model.
- ✅ Network-perimeter / VPCE deny policies correctly exempt AWS service principals.
Because all of these pass, the symptom actively steers you toward the wrong layer. In this case, the problem isn't permission. It's the KMS key resolution.
This is different from the documented Access Denied error, "Access denied Inventory export for 2021-02-19 failed because S3 doesn't have access to the destination bucket or KMS key. Ask the owner of the destination bucket or KMS key to grant the necessary access and then try again." That error explicitly names permissions as the cause, so you know where to look, while the "internal error" in this article gives you nothing to go on.
One cause: a bare KMS alias in the destination's default encryption
The destination bucket's SSE-KMS default encryption referenced the KMS key by a form that carries no account context, i.e. a bare alias (alias/my-inventory-key, with no account or region), or equivalently a bare key ID (the key UUID alone, e.g. 1234abcd-12ab-34cd-56ef-1234567890ab) - rather than a fully qualified key ARN (arn:aws:kms:<region>:<dest-acct-id>:alias/my-inventory-key or arn:aws:kms:<region>:<dest-acct-id>:key/<key-id>).
S3 Inventory delivery is an AWS service operation. AWS requires a fully qualified KMS key ARN for cross-account and service operations, because a reference with no account context (bare alias or bare key ID) resolves in the requester's account by default and cannot be resolved to a specific key in the delivery context. When S3 attempts GenerateDataKey to encrypt the report, the reference is unresolvable and the operation fails (surfaced in the console as the generic "internal error").
Two facts from the AWS documentation combine to make this both real and silent:
- From the S3 API reference (
ServerSideEncryptionByDefault, theKMSMasterKeyIDfield): "If you are using encryption with cross-account or Amazon Web Services service operations, you must use a fully qualified KMS key ARN." - From the
PutBucketEncryptionAPI reference: "Amazon S3 doesn't validate the KMS key ID provided in PutBucketEncryption requests."
So S3 accepts the bare-alias default-encryption configuration at config time without any error, and the misconfiguration only manifests later, at the delivery attempt.
How you end up in this state
A bare alias can be set on a bucket's default encryption via the AWS CLI (aws s3api put-bucket-encryption) or via infrastructure-as-code (CloudFormation/CDK/Terraform). In all of these paths, S3 accepts the bare alias / key ID without validation. There is no config-time error to warn you, regardless of how the value is applied. Which is exactly why this is easy to introduce and hard to catch.
Note: this concerns the destination bucket's default encryption (
KMSMasterKeyIDset viaput-bucket-encryption), which accepts a bare alias without validation. Do not confuse it with the inventory configuration's ownEncryption.SSEKMS.KeyIdfield, which is a different setting that does validate at config time. Setting that field to a bare key ID or a bare alias is rejected immediately:An error occurred (InvalidKmskeyId) when calling the PutBucketInventoryConfiguration operation: Invalid kms key id ARN.
Both the bare key ID and the bare alias (alias/<name>) were tested and produce this same error. Note the mismatch worth being aware of: the SSEKMS API data type documents this field only as "the ID of the ... KMS ... symmetric encryption customer managed key" (Type: String, no format constraint), yet the runtime requires a fully qualified ARN. The error message is the authoritative signal here and the field being labeled "the ID" is exactly why passing a bare ID is a natural mistake.
Reproduced: the exact behavior, isolated to key-reference form
All four rows below were reproduced in a sandbox; the only variable changed between them is the form of the KMS key reference in the destination bucket's default encryption, with bucket policy, key policy, and all permissions held identical and correct throughout.
| # | KMSMasterKeyID form | Example | Inventory delivery result |
|---|---|---|---|
| 1 | Bare alias | alias/my-inventory-key | ❌ Fails - "internal error" |
| 2 | Bare key ID | 1234abcd-12ab-34cd-56ef-1234567890ab | ❌ Fails - "internal error" |
| 3 | Alias ARN | arn:aws:kms:<region>:<dest-acct-id>:alias/my-inventory-key | ✅ Delivered |
| 4 | Key ARN | arn:aws:kms:<region>:<dest-acct-id>:key/<key-id> | ✅ Delivered |
What this proves: the bare alias / ID existed in the destination/bucket-owner account and still failed, while both forms that pin an account (alias ARN and key ARN) succeeded. So the resolution does not happen in the bucket-owner account (expected and documented). The reference must carry account context for the service delivery path to resolve the key.
The fix
Set the destination bucket's default-encryption KMSMasterKeyID to the fully qualified key ARN:
arn:aws:kms:<region>:<dest-acct-id>:key/<key-id>
No permission changes are required. The bucket policy and key policy that were already in place are correct. Only the key reference form changes.
AWS CLI:
aws s3api put-bucket-encryption --bucket amzn-s3-demo-inventory-destination --server-side-encryption-configuration '{ "Rules": [{ "ApplyServerSideEncryptionByDefault": { "SSEAlgorithm": "aws:kms", "KMSMasterKeyID": "arn:aws:kms:<region>:<dest-acct-id>:key/<key-id>" }, "BucketKeyEnabled": true }] }'
Console: on the destination bucket, Properties → Default encryption → Edit, choose Enter AWS KMS key ARN, and paste the full ...:key/<key-id> ARN (not the bare alias).
An alias can still be used, but it must be referenced as a fully qualified alias ARN:
arn:aws:kms:<region>:<dest-acct-id>:alias/<alias-id>
Alternative fix: specify the key ARN in the inventory configuration itself
Instead of correcting the destination bucket's default encryption, you can leave it as-is and have the inventory configuration specify its own encryption key. The S3 User Guide describes these as two alternative modes: "When you configure server-side encryption for your inventory report, you can use the bucket settings for default encryption or you can specify an encryption key." When the inventory configuration sets Encryption.SSEKMS.KeyId, that key is used to encrypt the delivered report instead of the destination bucket's default encryption. So the broken bare reference on the bucket default is never consulted.
Two constraints carry over:
- The
KeyIdmust be a fully qualified ARN. The inventory configuration validates this field at config time and rejects a bare key ID or bare alias withInvalidKmskeyId: Invalid kms key id ARN.(see the Note above). - The KMS key policy must already grant
s3.amazonaws.comthekms:GenerateDataKey*/kms:Encryptpermissions for the referenced key.
AWS CLI:
aws s3api put-bucket-inventory-configuration --bucket <source-bucket> --id <inventory-id> --inventory-configuration '{ "Destination": { "S3BucketDestination": { "Bucket": "arn:aws:s3:::amzn-s3-demo-inventory-destination", "Format": "CSV", "Encryption": { "SSEKMS": { "KeyId": "arn:aws:kms:<region>:<dest-acct-id>:key/<key-id>" } } } }, "IsEnabled": true, "Id": "<inventory-id>", "IncludedObjectVersions": "Current", "Schedule": { "Frequency": "Daily" } }'
Which fix to choose:
- Fix the bucket default encryption (recommended): corrects the misconfiguration for every consumer of that bucket's default encryption (this inventory, any other inventory configurations, any other AWS service delivery that relies on the default, and cross-account writers).
- Specify the key in the inventory configuration (targeted): fixes only this inventory report's delivery. The destination bucket's default encryption is still misconfigured and will still fail for anything else that relies on it. This is the right lever when you don't control the destination bucket's default encryption (for example, a cross-account destination owned by another team) but you do control your inventory configuration.
Verify the fix
1. Confirm the stored value is actually a fully qualified key ARN (or alias ARN):
aws s3api get-bucket-encryption --bucket amzn-s3-demo-inventory-destination
KMSMasterKeyID should read arn:aws:kms:<region>:<dest-acct-id>:key/<key-id> or arn:aws:kms:<region>:<dest-acct-id>:alias/<alias-id>.
For checking if the inventory configuration specifies the KMS key:
aws s3api get-bucket-inventory-configuration --bucket amzn-s3-demo-inventory-source --id example
2. Wait for the next scheduled inventory run, then confirm the report object lands in the destination and the configuration's last run shows success.
Confirming the key reference
How the stored key reference displays depends on its form:
On the console -
- A bare alias displays as the alias (alias/my-inventory-key). This is your diagnostic tell: a bucket throwing inventory "internal error" whose default-encryption key shows as a bare alias is the smoking gun.
- A bare key ID (1234abcd-...) displays as only the key ID. Another tell that points to the misconfiguration.
- A full alias ARN is resolved and displayed as the underlying key ARN (...:key/...). This is a correct configuration.
With CLI- This will show the KMS key form as well, either the full ARNs (arn:aws:kms:<region>:<dest-acct-id>:key/<key-id> or arn:aws:kms:<region>:<dest-acct-id>:alias/<alias-id>) or just the base ID or alias ( alias/name or 1234abcd-12ab-34cd-56ef-1234567890ab)
Related: a sibling failure with a different fix
S3 Server Access Logging has a closely related failure mode, delivery to a destination bucket with SSE-KMS default encryption, but the opposite resolution: server access log delivery requires SSE-S3 and does not support a customer-managed KMS key at all, so the fix there is to switch the destination to SSE-S3. See the AWS Knowledge Center article "Why didn't my Amazon S3 server access logs get delivered to my bucket?". For S3 Inventory, by contrast, the destination can use a customer-managed KMS key, it just has to be referenced by a fully qualified key ARN.
References
- Why can't I generate an Amazon S3 Inventory report?: https://repost.aws/knowledge-center/s3-inventory-report
- Amazon S3 API Reference - ServerSideEncryptionByDefault (KMSMasterKeyID field): "If you are using encryption with cross-account or Amazon Web Services service operations, you must use a fully qualified KMS key ARN." https://docs.aws.amazon.com/AmazonS3/latest/API/API_ServerSideEncryptionByDefault.html
- Amazon S3 API Reference - PutBucketEncryption: "Amazon S3 doesn't validate the KMS key ID provided in PutBucketEncryption requests." https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketEncryption.html
- Amazon S3 User Guide - SSE-KMS, "Using SSE-KMS encryption for cross-account operations": "If you use a KMS key alias instead, AWS KMS resolves the key within the requester's account..." https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingKMSEncryption.html
- AWS CLI Reference - put-bucket-encryption: https://docs.aws.amazon.com/cli/latest/reference/s3api/put-bucket-encryption.html
- AWS CLI Reference - put-bucket-inventory-configuration: https://docs.aws.amazon.com/cli/latest/reference/s3api/put-bucket-inventory-configuration.html
- AWS CLI Reference - get-bucket-inventory-configuration: https://docs.aws.amazon.com/cli/latest/reference/s3api/get-bucket-inventory-configuration.html
- Topics
- Storage
- Language
- English
Relevant content
asked 5 years ago
- Accepted Answer
asked 8 years ago
AWS OFFICIALUpdated 2 years ago
AWS OFFICIALUpdated 6 months ago