V8 Node v24.15.0, V8 13.6.233.17 上でパーサーを実行して確認しました。
"undefined" is not valid JSON
JSON.parseにundefinedを渡しました。それは文字列"undefined"に変換されますが、JSONにはそのようなリテラルがないため、位置0で失敗します。本当の問題は、そのundefinedがどこから来たのかです。答えはおおよそ3つしかありません。
次のような書き方で見かけることもあります
- Unexpected token u in JSON at position 0
V8は2022年に、JSONのエラーメッセージのほとんどを書き換えました。検索結果に出てくるのはいまだに古い文言がほとんどですが、現行のランタイムはどれもそれを出力しません。
JSONを貼り付けて、壊れている箇所を正確に確認する
入力
貼り付けたものがブラウザの外に出ることはありません。 connect-src の許可リストにより、これは約束ではなくブラウザによる保証になっています。 自分で確かめる
実際の原因
どれが答えになることが多いか、その順に並べています。
-
01 一度も設定されていないストレージのキー
localStorage.getItemはキーが存在しないときnullを返し、JSON.parse(null)は実際には動きます。しかし、そのキーに一度でも文字列"undefined"が書き込まれていた場合、読み戻すたびにこのエラーがまさに発生します。キーを消すまでずっとです。
壊れる例
localStorage.setItem('token', someUndefinedValue); // writes "undefined" JSON.parse(localStorage.getItem('token'));動く例
const raw = localStorage.getItem('token'); const token = raw && raw !== 'undefined' ? JSON.parse(raw) : null; -
02 非同期の値をawaitしていない
Promiseから、あるいはまだ読み込まれていないstateからプロパティを読むと、undefinedになります。データが届く前にパースが走っているのです。
壊れる例
const data = JSON.parse(fetchUser().body);動く例
const res = await fetchUser(); const data = JSON.parse(await res.text()); -
03 存在しないプロパティ
フィールド名の変更、タイプミス、あるいは形が変わったAPIなど。ペイロードがobj.resultを使っているのにobj.dataを読むと、ほかに何の警告もなくundefinedになります。
よくある質問
- なぜJSON.parse(null)は動いて、JSON.parse(undefined)は動かないのですか?
- どちらもまず文字列に変換されます。nullは"null"になり、これは妥当なJSONドキュメントなのでパースが通り、nullが返ります。undefinedは"undefined"になりますが、JSONにはそれに対応するリテラルがありません。
- 文字列"undefined"が入ったキーを消すには?
- localStorage.removeItem(key) を使うか、上に示したように読み取り側でガードしてください。壊れた値はリロードをまたいで残るため、このエラーはマシンによって出たり出なかったりするように見えることがよくあります。