本文へスキップ
jsonbeautifiers
日本語
V8 Node v24.15.0, V8 13.6.233.17 上でパーサーを実行して確認しました。

"[object Object]" is not valid JSON

JSON.parseは文字列を期待します。オブジェクトを渡すと、JavaScriptはまずそのオブジェクトを文字列に変換し、既定の変換は"[object Object]"というそのままのテキストを生みます。そのためパーサーは位置1の文字oで失敗します。データに問題はありません。余計なのはparseの呼び出しのほうです。

次のような書き方で見かけることもあります

  • Unexpected token o in JSON at position 1

V8は2022年に、JSONのエラーメッセージのほとんどを書き換えました。検索結果に出てくるのはいまだに古い文言がほとんどですが、現行のランタイムはどれもそれを出力しません。

JSONを貼り付けて、壊れている箇所を正確に確認する

入力

貼り付けたものがブラウザの外に出ることはありません。 connect-src の許可リストにより、これは約束ではなくブラウザによる保証になっています。 自分で確かめる

実際の原因

どれが答えになることが多いか、その順に並べています。

  1. 01 その値はすでにパース済みだった

    axios、jQuery.ajax、そして多くのAPIクライアントは、Content-Typeがそう示していればJSONを代わりにパースしてくれます。その結果をもう一度パースすると、このエラーになります。

    壊れる例

    const res = await axios.get('/api/user');
    const user = JSON.parse(res.data);   // res.data is already an object

    動く例

    const res = await axios.get('/api/user');
    const user = res.data;
  2. 02 stringifyせずにオブジェクトを保存した

    localStorageとsessionStorageは文字列を保存します。オブジェクトを渡すとString(obj)が呼ばれ、"[object Object]"というそのままのテキストが書き込まれます。その時点でデータは失われており、単に読めないだけではありません。

    壊れる例

    localStorage.setItem('user', user);
    const back = JSON.parse(localStorage.getItem('user'));

    動く例

    localStorage.setItem('user', JSON.stringify(user));
    const back = JSON.parse(localStorage.getItem('user'));
  3. 03 テンプレート文字列にオブジェクトを埋め込んだ

    `{"user": ${user}}`のようにリクエストボディを組み立てると、オブジェクトではなく"[object Object]"が挿入されます。オブジェクトを組み立てて、全体をstringifyしてください。

    壊れる例

    body: `{"user": ${user}}`

    動く例

    body: JSON.stringify({ user })

よくある質問

「Unexpected token o in JSON at position 1」はどうなったのですか?
同じ間違いに対する、2022年より前のV8の文言です。そのoは"[object Object]"という文字列の2文字目でした。現在のメッセージは代わりに問題のテキストを引用しており、そのほうがはるかに有用です。
防御的に書くには?
typeof value === "string" ? JSON.parse(value) : value。自分の制御が及ばない境界では妥当なガードです。ただし自分のコードの内側では、そもそもどちらが来るのかを分かっているほうが望ましいです。

今すぐ直す

上のツールにペイロードを貼り付けるか、この用途のために作られたツールに直接進んでください。

ペイロードを調べる