Error [TypeError: crypto.hash is not a function]

TypeError: crypto.hash is not a function:新しい Node の crypto.hash が古い版で無いときの直し方

FIX SUMMARY verified
Applies when
node:20.11.1-alpinecall to crypto.hash on Node < 20.12 / 21.0-21.6

Verified: reproduced in node:20.11.1-alpine, then the TypeError: crypto.hash is not a function signature was gone after the fix (exit 0).

新しいドキュメントやサンプルで見かけた crypto.hash() をそのまま使ったら、手元やサーバーの Node で次のエラーが出て落ちることがあります。

TypeError: crypto.hash is not a function
    at Object.<anonymous> (/app/index.js:3:20)

コピペ検索用の表記ゆれです。いずれも同じ原因です。

  • TypeError: crypto.hash is not a function
  • crypto.hash is not a function

これまで紹介してきた「古い Node に新しい API が無い」ケースと向きが逆で、crypto.hash が追加されたのが Node 20.12.0(と 21.7.0)と新しく、それより前の版には無いのが原因です。crypto モジュール自体はどの版にもありますが、hash メソッドだけが新しい版にしか無いため、is not defined ではなく is not a function という形で出ます。

厄介なのは版の並びです。crypto.hash現行 LTS だった 20 系に 20.12.0 で入り、当時の最新だった 21 系には 21.7.0 で入りました。そのため「バージョン番号が大きいほうには必ずある」とは限りません。21.6 は 20.12 より番号が大きいのに crypto.hash は無い、という逆転が起きます。「新しめの Node なら大丈夫だろう」で 21.6 を使っていると、20.12 では動くコードがこちらでだけ落ちます。

どの版に crypto.hash があるのか

crypto.hash(ハッシュ値を一発で計算する関数)は複数のリリース系列に分けて追加されました。系列ごとに入った版が違います。

Node の版crypto.hash挙動
20.11 以前無しTypeError: crypto.hash is not a function
20.12.0 以降(20 系)有りそのまま使える
21.0〜21.6無しTypeError: crypto.hash is not a function
21.7.0 以降(21 系)有りそのまま使える
22 以降有りそのまま使える

同じ機能でも、LTS 系列(20)と現行系列(21)で入ったマイナー版がずれています。だから 20.12 と 21.6 のように「古いほうにはあって、新しいほうには無い」区間ができます。単純に版番号の大小では判断できないのがこのエラーの引っかかりどころです。

crypto.hash は何をするものか

crypto.hash(algorithm, data, outputEncoding) は、ハッシュ値を1行で計算するための関数です。従来は crypto.createHash(...).update(...).digest('hex') と3段階で書いていた処理を、1回の呼び出しにまとめたものです。短く書けるぶん新しいサンプルで見かけますが、その分だけ対応する版が新しく、古い版に持ち込むと落ちます。加えて crypto.hash は追加後しばらく実験的(Stability 1・experimental)扱いで、Node 22 系でもその位置づけのままでした。長く保守するコードでは、次の解決1(createHash に戻す)のほうが版・安定度の両面で無難です。

再現(最小構成)

次の1ファイルを置きます。

// index.js
const crypto = require('node:crypto');

console.log(crypto.hash('sha256', 'errfix', 'hex'));

これを Node 20.11 以前や 21.0〜21.6 で node index.js すると TypeError: crypto.hash is not a function が出て、終了コードは 1 になります。Node 20.12 以降(または 21.7/22 以降)なら SHA-256 のダイジェスト(16 進文字列)が表示されます。

解決

1. crypto.createHash に書き換える(どの版でも動かしたいとき)

crypto.hashcreateHash().update().digest() の短縮版なので、元の書き方に戻せばどの版でも動きます。古い Node をサポート対象に含むなら、こちらが確実です。

// index.js(createHash に戻した)
const crypto = require('node:crypto');

const digest = crypto.createHash('sha256').update('errfix').digest('hex');
console.log(digest);

新旧どちらの版でも通したいコードなら、crypto.hash があるときだけ使う分岐にできます。

const crypto = require('node:crypto');

function sha256Hex(input) {
  if (typeof crypto.hash === 'function') {
    return crypto.hash('sha256', input, 'hex');
  }

  return crypto.createHash('sha256').update(input).digest('hex');
}

2. Node を上げる(crypto.hash を使い続けたいとき)

短い crypto.hash の書き方を使い続けるなら、実行する Node を対応版へ上げます。20 系なら 20.12.0 以降、22 以降ならどの版でも使えます。今から揃えるなら、サポート中の LTS(22 以降)にするのが安全です。20 系に留まる事情があるなら 20.12.0 以降ですが、20 も 21 もすでに EOL(サポート終了)である点は踏まえてください。ここで気をつけるのは、CI・本番の Docker ベースイメージが crypto.hash の入った版かどうかで、番号の大小ではなく「20.12 以降 / 21.7 以降 / 22 以降」で確認することです。

切り分け(似ているが原因が違うもの)

  • 番号が大きい Node なのに落ちるcrypto.hash は 20.12 で LTS に入り、21 系は 21.7 まで入りませんでした。21.6 のように「20.12 より新しいのに無い」版があるのはこのためです。使っている版が 20.12 以降 / 21.7 以降 / 22 以降のいずれかに当てはまるかで判断してください。
  • 逆向き(古い Node に新しい標準 API が無い)crypto.hash は「新しい API を古い版に持ち込んで落ちる」例ですが、fetchstructuredCloneAbortController のように「古い Node にそもそも無い」グローバル API も、同じく is not definedis not a function で落ちます。原因は共通で、対処は Node を上げるか従来の書き方・ポリフィルに寄せるかです。fetchReferenceError: fetch is not defined の直し方crypto.randomUUIDTypeError: crypto.randomUUID is not a function の直し方 を参照してください。
  • cryptoundefined で落ちたCannot read properties of undefined (reading 'hash') のように crypto 自体が無いなら、これは版の問題ではなく require('node:crypto')(ESM なら import)の書き忘れです。

検証(machine-verified)

この修正は node:20.11.1-alpine のバージョン固定コンテナ内で再現し、修正後に TypeError: crypto.hash is not a function のシグネチャが消えることを機械で確認しています。

verify — run-case.mjs
$ node run-case.mjs node/crypto-hash-not-a-function
● reproduce TypeError: crypto.hash is not a function present ✓
● apply fix exit 0
● re-run TypeError: crypto.hash is not a function gone ✓
PASS verified · node:20.11.1-alpine · signature gone