FiloSottile/age · critical
failed to decrypt and authenticate payload chunk, file may b
Error message
failed to decrypt and authenticate payload chunk, file may be corrupted or tampered with
What it means
The ChaCha20Poly1305 AEAD Open call failed on a payload chunk, meaning authentication (MAC) or decryption failed. Since the header MAC already passed, this means the encrypted payload was modified, corrupted, or encrypted with a different file key. The reader treats any single bad chunk as a fatal error for the whole file.
Source
Thrown at internal/stream/stream.go:150
return false, errors.New("last chunk is empty, try age v1.0.0, and please consider reporting this")
}
in = in[:n]
last = true
setLastChunkFlag(&r.nonce)
case err != nil:
return false, err
}
outBuf := make([]byte, 0, ChunkSize)
out, err := r.a.Open(outBuf, r.nonce[:], in, nil)
if err != nil && !last {
// Check if this was a full-length final chunk.
last = true
setLastChunkFlag(&r.nonce)
out, err = r.a.Open(outBuf, r.nonce[:], in, nil)
}
if err != nil {
return false, errors.New("failed to decrypt and authenticate payload chunk, file may be corrupted or tampered with")
}
incNonce(&r.nonce)
r.unread = r.buf[:copy(r.buf[:], out)]
return last, nil
}
func incNonce(nonce *[chacha20poly1305.NonceSize]byte) {
for i := len(nonce) - 2; i >= 0; i-- {
nonce[i]++
if nonce[i] != 0 {
return
}
}
// The counter is 88 bits, this is unreachable.
panic("stream: chunk counter wrapped around")
}
View on GitHub (pinned to b74dce4cdb)
Solutions
- Confirm you are using the correct identity/private key that the file was encrypted for.
- Re-download or re-copy the file and verify its checksum against the sender.
- Re-encrypt from the original plaintext if the source is corrupted beyond repair.
- Check that no transport step (FTP ascii mode, editor save) mangled the binary ciphertext.
Example fix
// before
r, _ := age.Decrypt(input, wrongIdentity) // payload chunks fail auth
// after
r, err := age.Decrypt(input, correctIdentity)
if err != nil { return fmt.Errorf("decrypt: %w", err) } Defensive patterns
Strategy: try-catch
Try / catch
if _, err := io.Copy(out, r); err != nil {
if strings.Contains(err.Error(), "failed to decrypt and authenticate payload chunk") {
return errors.New("wrong key or corrupted/tampered file")
}
return err
} Prevention
- Verify you hold the identity the file was encrypted for before long processing.
- Use binary-safe transfer (no text-mode FTP, no editor round-trips) for .age files.
- Distribute checksums alongside ciphertext and verify before decrypting.
When it happens
Trigger: stream.Reader.readChunk calls r.a.Open and it returns a non-nil error — wrong identity/key (mismatched file key), bit rot, truncated bit flips, or tampered ciphertext bytes within any chunk.
Common situations: Decrypting with the wrong identity (file encrypted for someone else); corrupted downloads or damaged storage; malicious modification of the .age file; copying the file in text mode that altered bytes.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
AI-assisted analysis of FiloSottile/age@b74dce4cdb (2026-08-31).
Data as JSON: /api/errors/a9d82a98f8141e38.
Report an issue: GitHub.