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

  1. Wrap raw ArrayBuffer/SharedArrayBuffer in a view: new Uint8Array(buf) or Buffer.from(buf).
  2. For strings, pass them directly as data with inputEncoding, or Buffer.from(str, enc) explicitly.
  3. 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

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


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/a8df0a14cf7097a2. Report an issue: GitHub.