denoland/deno · error · ERR_INVALID_ARG_TYPE

ERR_INVALID_ARG_TYPE

ERR_INVALID_ARG_TYPE

Error message

The "ikm" argument must be of type string or an instance of SecretKeyObject, ArrayBuffer, TypedArray, DataView, or Buffer. Received ${key}

What it means

prepareKey in ext/node/polyfills/internal/crypto/hkdf.ts accepts an ikm (input keying material) that is a KeyObject, any ArrayBuffer, or something toBuf can convert to a Buffer view (strings, TypedArrays, DataViews). If none of those apply it throws ERR_INVALID_ARG_TYPE listing the accepted shapes. Everything else in hkdf (salt, info) is coerced leniently, but the key must be real key material.

Source

Thrown at ext/node/polyfills/internal/crypto/hkdf.ts:122

      info,
      length,
    };
  },
);

function prepareKey(key: any) {
  if (isKeyObject(key)) {
    return key;
  }

  if (isAnyArrayBuffer(key)) {
    return createSecretKey(new Uint8Array(key as unknown as ArrayBufferLike));
  }

  key = toBuf(key as string);

  if (!isArrayBufferView(key)) {
    throw new ERR_INVALID_ARG_TYPE(
      "ikm",
      [
        "string",
        "SecretKeyObject",
        "ArrayBuffer",
        "TypedArray",
        "DataView",
        "Buffer",
      ],
      key,
    );
  }

  return createSecretKey(key);
}

function hkdf(
  hash: string,

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Convert the ikm to a Buffer or string before calling hkdf: Buffer.from(secret).
  2. If you have a WebCrypto CryptoKey, export it first: crypto.subtle.exportKey('raw', key) then pass the ArrayBuffer.
  3. If you hold a JWK, rebuild a KeyObject with crypto.createSecretKey(Buffer.from(jwk.k, 'base64url')) instead of passing the JWK itself.
  4. Add a type check at your own API boundary so bad values fail with your error message.

Example fix

// before
crypto.hkdfSync('sha256', 12345, salt, info, 32); // number ikm -> ERR_INVALID_ARG_TYPE

// after
crypto.hkdfSync('sha256', '12345', salt, info, 32);             // string
crypto.hkdfSync('sha256', Buffer.from('12345'), salt, info, 32); // or Buffer
Defensive patterns

Strategy: type-guard

Validate before calling

function assertIkm(key) {
  const ok = typeof key === 'string' || Buffer.isBuffer(key) ||
    ArrayBuffer.isView(key) || key instanceof ArrayBuffer ||
    (key && typeof key === 'object' && key.constructor?.name === 'KeyObject');
  if (!ok) throw new TypeError('hkdf key must be string/Buffer/TypedArray/ArrayBuffer/KeyObject');
}
assertIkm(ikm);
crypto.hkdfSync('sha256', ikm, salt, info, 32);

Type guard

function isHkdfKeyMaterial(v) {
  return typeof v === 'string' || ArrayBuffer.isView(v) ||
    v instanceof ArrayBuffer || crypto.KeyObject?.isKeyObject?.(v) === true;
}

Try / catch

try {
  crypto.hkdfSync('sha256', ikm, salt, info, 32);
} catch (e) {
  if (e.code === 'ERR_INVALID_ARG_TYPE' && /ikm/.test(e.message)) {
    throw new TypeError(`bad ikm from source X (${typeof ikm})`);
  }
  throw e;
}

Prevention

When it happens

Trigger: crypto.hkdfSync('sha256', 12345, salt, info, 32) (number); passing null/undefined, a plain object, or a boolean as key; passing a KeyObject-like wrapper (e.g. a JWK object or {k: '...'}) that is not an actual KeyObject.

Common situations: Reading a passphrase from an env var or JSON config and forgetting to convert it to string/Buffer; passing a parsed JWK where a SecretKeyObject is expected; passing a CryptoKey (WebCrypto object, not a Node KeyObject) into node:crypto hkdf.

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/66c1e89fdf765147. Report an issue: GitHub.