denoland/deno · error · TypeError
Invalid authentication tag length: ${tagByteLength}
Error message
Invalid authentication tag length: ${tagByteLength} What it means
For GCM, when createDecipheriv() received no explicit authTagLength option (_authTagLength === -1), the authentication tag must be exactly 16 bytes (128 bits); any other tagByteLength throws TypeError 'Invalid authentication tag length: N'. This was Node deprecation DEP0182 and is now a hard error — the polyfill matches Node's current behavior. Shorter tags (4-15 bytes) are legal only when authTagLength was declared at construction.
Source
Thrown at ext/node/polyfills/internal/crypto/cipher.ts:658
Decipheriv.prototype.setAuthTag = function (
buffer: any,
_encoding?: string,
) {
if (this._authTag) {
throw new ERR_CRYPTO_INVALID_STATE("setAuthTag");
}
// When no explicit `authTagLength` was given at decipher creation time, a
// GCM authentication tag must be the full 128 bits (16 bytes); shorter tags
// are only accepted when `authTagLength` is set. This used to be the DEP0182
// deprecation warning and is now a hard error (matching Node.js).
// deno-lint-ignore deno-internal/prefer-primordials -- `buffer` may be Buffer/TypedArray/DataView
const tagByteLength = buffer.byteLength;
if (
this._isGcmMode && this._authTagLength === -1 &&
tagByteLength !== 16
) {
throw new TypeError(
`Invalid authentication tag length: ${tagByteLength}`,
);
}
// deno-lint-ignore deno-internal/prefer-primordials -- `buffer` may be Buffer/TypedArray/DataView
op_node_decipheriv_auth_tag(this._context, buffer.byteLength);
this._authTag = buffer;
return this;
};
Decipheriv.prototype.setAutoPadding = function (autoPadding?: boolean) {
this._autoPadding = Boolean(autoPadding);
this._cache.lastChunkIsNonZero = this._autoPadding;
return this;
};
Decipheriv.prototype.update = function (
data: string | Buffer | ArrayBufferView,
inputEncoding?: any,View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Declare the expected length at construction: createDecipheriv('aes-128-gcm', key, iv, { authTagLength: tag.length }).
- Or make the encrypting side emit full 16-byte tags.
- Verify you are passing the actual tag: check slice offsets when splitting payload|tag, and assert tag.length matches the protocol.
Example fix
// before
const d = crypto.createDecipheriv('aes-128-gcm', key, iv);
d.setAuthTag(blob.subarray(blob.length - 8)); // 8-byte tag, no authTagLength -> TypeError
// after
const tagLen = 8;
const d = crypto.createDecipheriv('aes-128-gcm', key, iv, { authTagLength: tagLen });
d.setAuthTag(blob.subarray(blob.length - tagLen)); Defensive patterns
Strategy: validation
Validate before calling
function gcmDecipher(key: Buffer, iv: Buffer, tag: Buffer): crypto.DecipherGCM {
if (tag.length !== 16)
return crypto.createDecipheriv('aes-128-gcm', key, iv, { authTagLength: tag.length });
return crypto.createDecipheriv('aes-128-gcm', key, iv);
}
// gcmDecipher(key, iv, tag).setAuthTag(tag) never throws the length TypeError Try / catch
try { d.setAuthTag(tag); } catch (e) { if (e.message.startsWith('Invalid authentication tag length')) { d = crypto.createDecipheriv(algo, key, iv, { authTagLength: tag.length }); d.setAuthTag(tag); } else throw e; } Prevention
- Always pass { authTagLength: tag.length } when the protocol uses non-16-byte GCM tags.
- Standardize on full 16-byte tags unless a spec forces otherwise.
- Unit-test tag slicing offsets when splitting payload||tag blobs; assert tag.length matches the negotiated value.
When it happens
Trigger: createDecipheriv('aes-128-gcm', key, iv) followed by setAuthTag(tag.subarray(0, 8)) — a truncated tag without a declared length; interop with peers (Java/GnuTLS/BoringSSL) configured for short GCM tags; accidentally passing ciphertext, IV, or a mis-sliced portion of the payload instead of the tag.
Common situations: Upgrading Node/Deno where the DEP0182 warning became a hard error; splitting payload||tag blobs with an off-by-one slice length; protocols negotiated for 96-bit tags while the decrypt code assumes defaults.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED
- ERR_INVALID_ARG_TYPE
- ERR_INVALID_ARG_TYPE
- ERR_CRYPTO_UNKNOWN_CIPHER
- ERR_CRYPTO_INVALID_STATE
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/0973dd0c6f532eb1.
Report an issue: GitHub.