denoland/deno · error · TypeError
ERR_INVALID_ARG_TYPE
ERR_INVALID_ARG_TYPE
Error message
The "data" argument must be of type string or an instance of Buffer, TypedArray, or DataView. Received ${data} What it means
Cipheriv/Decipheriv .update() accepts only a string, Buffer/TypedArray, or DataView. The polyfill deliberately mirrors Node's `ArrayBuffer.isView(data)` check (see validateCipherUpdateData), so a raw ArrayBuffer or SharedArrayBuffer is rejected even though other crypto APIs (WebCrypto, toU8 helpers) accept array buffers. There is no implicit conversion: numbers, null, and plain objects fail the same check.
Source
Thrown at ext/node/polyfills/internal/crypto/cipher.ts:163
cipher === "aes256-wrap" || cipher === "id-aes128-wrap-pad" ||
cipher === "id-aes192-wrap-pad" || cipher === "id-aes256-wrap-pad";
}
function isStringOrBuffer(
val: unknown,
): val is string | Buffer | ArrayBuffer | ArrayBufferView {
return typeof val === "string" ||
isArrayBufferView(val) ||
isAnyArrayBuffer(val) ||
Buffer.isBuffer(val);
}
// Matches Node's `ArrayBuffer.isView(data)` check in
// `lib/internal/crypto/cipher.js`: accepts string, Buffer, TypedArray
// or DataView, but rejects raw ArrayBuffer / SharedArrayBuffer.
function validateCipherUpdateData(data: unknown): void {
if (typeof data !== "string" && !ArrayBufferIsView(data)) {
throw new ERR_INVALID_ARG_TYPE(
"data",
["string", "Buffer", "TypedArray", "DataView"],
data,
);
}
}
const NO_TAG = new Uint8Array();
function toU8(
input: string | Uint8Array | KeyObject | null,
): Uint8Array {
if (input == null) {
return new Uint8Array(0);
}
if (isKeyObject(input)) {
return op_node_export_secret_key(input[kHandle]);
}View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Wrap raw ArrayBuffer/SharedArrayBuffer in a view: new Uint8Array(buf) or Buffer.from(buf).
- For strings, pass them directly as data with inputEncoding, or Buffer.from(str, enc) explicitly.
- Route all update() calls through a helper that applies the type guard first.
Example fix
// before const ab: ArrayBuffer = await res.arrayBuffer(); cipher.update(ab); // ERR_INVALID_ARG_TYPE // after const ab: ArrayBuffer = await res.arrayBuffer(); cipher.update(new Uint8Array(ab)); // TypedArray view is accepted
Defensive patterns
Strategy: type-guard
Type guard
function isCipherUpdateData(v: unknown): v is string | Buffer | ArrayBufferView {
return typeof v === 'string' || ArrayBuffer.isView(v) || Buffer.isBuffer(v);
}
// usage
if (!isCipherUpdateData(data)) data = Buffer.from(data as string); // or wrap/reject Try / catch
try { cipher.update(data); } catch (e) { if (e.code === 'ERR_INVALID_ARG_TYPE' && /"data"/.test(e.message)) { cipher.update(new Uint8Array(data as ArrayBuffer)); } else throw e; } Prevention
- Always view-wrap ArrayBuffers: new Uint8Array(ab) before update().
- Type function parameters as string | Buffer | ArrayBufferView so invalid inputs fail at compile time.
- Keep one shared encode/encrypt helper so conversion happens in exactly one place.
When it happens
Trigger: cipher.update(new ArrayBuffer(16)); decipher.update(42); cipher.update({ data: 'x' }); passing a SharedArrayBuffer that is not wrapped in a typed-array view.
Common situations: Feeding an ArrayBuffer from fetch()/WebSocket responses directly into a node:crypto cipher; passing deserialized JSON values or numbers; refactors that swapped Buffer for ArrayBuffer when adopting WebCrypto-style code.
Understand the failure class
Background: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.
Related errors
- ERR_CRYPTO_UNKNOWN_CIPHER
- ERR_CRYPTO_INVALID_STATE
- Trying to add data in unsupported state
- ERR_UNKNOWN_ENCODING
- ERR_INVALID_ARG_VALUE
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/a8df0a14cf7097a2.
Report an issue: GitHub.