メインコンテンツへスキップ
#Web制作 約4分で読めます

JSONのパースエラー、原因はだいたいこの3つ

Unexpected token in JSON at position 4032——このエラーと何百回も戦ってわかった三大原因(末尾カンマ・クォート・見えない文字)と、エラー位置を一瞬で特定する方法。

SyntaxError: Unexpected token '}' in JSON at position 4032

深夜にこれが出たときの絶望感は、エンジニアなら共有できると思う。position 4032って、どこだよ。

JSONのパースエラーとは長い付き合いになるが、経験上、原因の9割は3つに絞られる。先に犯人リストを知っていれば、探す時間は劇的に短くなる。

犯人1: 末尾カンマ

{
  "name": "clvr",
  "tags": ["web", "ai"],
}

"ai"] の後ろのカンマ。JavaScriptのオブジェクトでは合法なので、コードを書く手癖でそのまま付けてしまう。JSONでは違法

配列やオブジェクトの要素を並べ替えたり、最後の行を削除したりした直後に発生しがちで、package.jsonを手で編集したあとのnpm installが謎に失敗するときは、まずこれを疑っていい。

逆パターンの「カンマ忘れ」も同罪。行を追加したときに前の行のカンマを付け忘れるやつで、エラー位置が「次の行の先頭」を指すので少し混乱する。

犯人2: クォートまわり

JSONの文字列とキーはダブルクォートのみ。シングルクォートは使えないし、キーのクォート省略もできない。

{ 'name': 'clvr' }   ← 全部ダメ
{ name: "clvr" }     ← キーがダメ

これもJavaScriptの手癖がそのまま事故になるパターン。もうひとつ厄介なのが、WordやSlackから値をコピペしたときに紛れ込む「スマートクォート」("")。見た目はほぼダブルクォートなのに別の文字なので、目視ではまず気づけない。

犯人3: 見えない文字

一番タチが悪い。過去に実際に踏んだものを挙げると——

  • BOM。WindowsのエディタやAPIレスポンスの先頭に付いてくる不可視文字。position 0でエラーが出たらほぼこれ
  • 全角スペース。設定ファイルをインデントしようとして混入。エディタ上では半角スペースと見分けがつかない
  • 改行コードや制御文字が文字列の中に生で入っているケース。ログをコピペしたときに多い

以前、同僚の環境でだけCIが落ちる事件があって、2時間調べた結果、設定JSONの中の全角スペース1個だった。ああいう時間は二度と過ごしたくない。

position 4032を人力で数えない

エラーメッセージのpositionは「先頭から何文字目か」でしかないので、そのままでは使いものにならない。エディタに貼って先頭から数える……のは無理なので、位置から行と列を割り出す必要がある。

やり方は単純で、position番目までの文字列に含まれる改行を数えれば行番号が出る。ただ、この作業を毎回やるのが面倒すぎて、ツールにした。

JSON整形・検証ツール

壊れたJSONを貼って「検証」を押すと、エラーの行・列と、その周辺の文字列を表示する。スマートクォートも全角スペースも、周辺表示を見れば一発でわかる。ついでに整形(インデント2/4/タブ)、圧縮、キーのアルファベット順ソートもできる。処理はブラウザ内で完結するので、APIキーが入ったままの設定ファイルを貼っても外に漏れない。

コマンドライン派ならjqでも同じことができる。

jq '.' config.json   # 正常なら整形して出力、壊れていればエラー位置を表示

CIに組み込むならこっちが便利で、JSONを生成するスクリプトの後ろにjq emptyを挟んでおくと、壊れたJSONがデプロイまで流れていく事故を防げる。


最後にひとつ。「JSONにコメントを書きたい」と思ったことがあるなら、それは正常な感覚だが、JSONの仕様上は書けない。VS Codeの設定ファイルなどで見かけるコメント付きのやつはJSONCという別物なので、あれを普通のパーサーに食わせると当然死ぬ。これも地味によくある事故なので、頭の隅に置いておいてほしい。

#JSON #デバッグ #JavaScript
シェア