Safeguard
Developer Tools•

Why does AES-GCM decryption fail with an authentication error?

A GCM auth failure means the tag did not verify: wrong key, IV, tag or associated data, or changed bytes. A debugging checklist and why not to bypass it.

Safeguard Security Team
4 min read

An authentication error means the tag did not verify. Either the ciphertext, IV, tag or associated data differs from what was encrypted, the key is wrong, or the data was tampered with. Do not work around it. The Node.js documentation says a failed check means the ciphertext should be discarded.

What GCM is checking

GCM is an authenticated mode. NIST describes it as an algorithm for authenticated encryption with associated data. Encryption produces ciphertext and a tag. Decryption recomputes the tag from the key, IV, ciphertext and any associated data, and fails if it does not match.

That is a feature. A mode without this check would hand you altered plaintext and say nothing.

Debugging checklist

CheckWhat goes wrong
Same keyA rotated key, a key for another environment, or a key read with a different encoding
Same IVThe IV was regenerated on decrypt, or cut to a different length
Same tagThe tag was lost, truncated or appended in a different position
Same tag lengthThe Node docs say setAuthTag throws if the tag length is invalid or does not match the authTagLength option
Same associated dataAAD must match byte for byte on both sides, if used
Ciphertext unchangedA proxy, database column or text encoding altered the bytes
Encoding round tripBase64, hex or string conversion corrupted binary data

Where the bytes get changed

Most real cases are storage and transport. A binary value saved into a text column and trimmed. A newline added by a command line tool. Base64 with URL safe and standard alphabets mixed. A character set conversion on a string that was really bytes.

Log lengths, not contents. If the IV is not the length you expect, or the blob is shorter than IV plus tag, you have found the problem.

Order of operations in Node.js

The Node docs say getAuthTag should only be called after encryption is complete, and that on decryption, if no tag is provided or the ciphertext has been tampered with, final will throw. So set the tag before calling final, and wrap the call so a throw becomes a rejected message.

What not to do

  1. Do not catch the error and use whatever partial plaintext was produced.
  2. Do not switch to an unauthenticated mode to make the error go away. OWASP says CTR and CBC offer no authenticity guarantee and need separate authentication.
  3. Do not log the key or the plaintext while debugging.
  4. Do not retry with other keys indefinitely from user input, since that can become an oracle.

If it began after a deployment

Compare what changed: key source, library version, serialization format, or a new service that touches the data. If you rotated keys, confirm each blob carries a key identifier so the right key is chosen. OWASP says tagging data with its key ID and keeping old keys to decrypt is an accepted approach.

When it really is tampering

Treat repeated failures from one source as a signal. Log the event with the record id, not the data, and alert if the rate rises. Failed authentication on stored data may mean corruption, or an attack.

Safeguard can generate an SBOM and scan your dependencies, so outdated cryptography libraries with known advisories show up in one inventory, and policies can gate a build on them. A free scan is at gold.safeguard.sh/scan.

Quick check

Can I just ignore the tag?

No. Ignoring it removes the integrity guarantee, and an attacker can change data undetected.

Why does it work on my machine but not in production?

Usually a different key, a different encoding in storage, or a proxy changing bytes. Compare lengths and key ids first.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.