BadDigest, InvalidRequest, and the CompleteMultipartUpload Checksum Contract
Publication update, 2026-09-17: The streaming-checksum follow-up (PR #143) shipped in Server 20260916. Coordinated upgrades, opt-in prerequisites and remaining limitations still apply. Dated source-status and validation records below retain their original scope.
The repairs for #48 and #50 are included in Server 20260903. This record supersedes the August proposal to leave CRC64NVME canonicalization unchanged.
Why validation belongs at completion
Initiation selects the checksum algorithm and object type; each part records
its checksum. Completion must validate the final value and any explicit type
assertion against that stored contract. A request cannot change COMPOSITE to
FULL_OBJECT just because both share the same base algorithm, or bypass the
assertion by omitting the final digest.
The repair distinguishes an omitted type from an explicit type and normalizes only internal representation flags. It uses operation-specific error types, leaving UploadPart and the global checksum-mismatch mapper unchanged.
Current error contract
All failures below return HTTP 400 and do not commit a new completed object.
| Request condition | S3 error |
|---|---|
| Wrong full-object or composite object digest | BadDigest |
| Explicit supported type differs from the initiated type, including a type-only assertion | BadDigest |
| Unknown or lowercase type token | InvalidArgument |
| Completion algorithm differs from the initiated algorithm | InvalidArgument |
| Missing required composite part checksum | InvalidRequest, naming the algorithm and part |
| CRC64NVME with COMPOSITE at initiation | InvalidArgument |
| CRC64NVME value with COMPOSITE rejected by checksum parsing at completion | InvalidArgument |
| Bare COMPOSITE type at completion of a CRC64NVME FULL_OBJECT upload | BadDigest |
| Incorrect client checksum during UploadPart | Existing XAmzContentChecksumMismatch |
For FULL_OBJECT, part checksums may be omitted; any supplied values remain
validated. Matching type-only assertions are allowed. An omitted optional type
does not assert COMPOSITE. SHA1/SHA256 with FULL_OBJECT are rejected by the
algorithm/type parser before the stored-type comparison.
CRC64NVME decision and source evidence
The original review deferred #50 pending evidence; that is historical, not the current contract. PR #93 rejects the invalid algorithm/type combination in headers and trailers, and PR #96 removes completion’s canonicalization. Both precede the 20260903 tag. Completion can fail at either parsing or stored-type comparison, which explains the two distinct error codes above.
The initial mapping is in PR #74, with
the explicit type follow-up 7e079ff05 merged through
PR #85. Current
handler tests
exercise full-object and composite mismatches, type-only assertions, invalid
tokens and both CRC64NVME rejection stages. This is committed regression
coverage, not a claim that this documentation update reran all Server tests.
Separate streaming-checksum follow-up
PR #143, following @cbornet’s
#107, handles an aws-chunked request
that advertises x-amz-trailer but supplies its checksum in a header, as used by
the AWS Java SDK v2. It also rejects an invalid header-delivered value instead
of dropping validation. This later repair is on main and not in Server
20260903. It is separate from completion error mapping.
Compatibility and remaining boundaries
Callers that inspect error codes now see checksum/type failures as BadDigest
and missing composite values as InvalidRequest. Successful checksum-free
uploads and ETag semantics are unchanged. No metadata migration is required.
Several narrower differences remain: providing a final digest when initiation
recorded no checksum is rejected as BadDigest; composite part-count and value
mismatches share one description; a -N suffix on a full-object checksum is
not itself validated as a part count. These are documented observations, not
claims of separately filed public issues or complete AWS parity.