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

  1. Confirm you are using the correct identity/private key that the file was encrypted for.
  2. Re-download or re-copy the file and verify its checksum against the sender.
  3. Re-encrypt from the original plaintext if the source is corrupted beyond repair.
  4. 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

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

Related errors


AI-assisted analysis of FiloSottile/age@b74dce4cdb (2026-08-31). Data as JSON: /api/errors/a9d82a98f8141e38. Report an issue: GitHub.