BadDigest 🔌 API

Upload error: checksum mismatch (BadDigest / Content-MD5 did not match / XAmzContentSHA256Mismatch)

The server computed a different checksum for the data it received than the one your client declared, so it rejected the upload as corrupted.

Seen on: REST API

Meaning

Integrity checks (Content-MD5, x-amz-checksum-*, x-amz-content-sha256, custom SHA-256 fields) catch data damaged in transit. S3 returns BadDigest (“The Content-MD5 you specified did not match what we received”) or XAmzContentSHA256Mismatch; GCS and other APIs have equivalents.

Most mismatches come from the client: hashing a different version of the data than was sent (before compression, re-encoding or newline conversion), or a stream that was partly consumed before upload.

Common causes

  • Checksum computed over different bytes (before gzip, text-mode newline conversion, re-encoding)
  • Stream partially read before upload, or retried without rewinding
  • Network/proxy corruption or a truncated transfer
  • Wrong encoding of the checksum (hex vs base64)

⚡ Quick fix

  1. Hash exactly the bytes you send, after any transformation
  2. Rewind or recreate the stream on retry
  3. Check whether the API wants base64 or hex

Detailed fix by platform

Node.js

  1. javascript
    import { createHash } from 'node:crypto';
    const md5 = createHash('md5').update(buf).digest('base64');   // Content-MD5 is base64, not hex
    await s3.putObject({ Bucket, Key, Body: buf, ContentMD5: md5 });

AWS CLI

  1. aws s3 cp big.zip s3://bucket/ --checksum-algorithm SHA256

How to diagnose

  1. Values — Client vs server checksum
  2. Bytes — Hash computed before or after compression/encoding?
  3. Retries — Is the body stream reused?

🧠 Still stuck? Analyze your error

Paste the full message, response headers or stack trace — we'll detect the platform and point to the most likely cause.