JSONが読み込めない原因は「最後のカンマ」と「引用符」──エラー別チェックリスト
JSONが読み込めない原因で多いのは、最後の要素のあとのカンマ、シングルクォートや全角の引用符、コメントです。RFC 8259の規則と、Node.jsとPythonで実際に試した結果をもとに、12のエラーを症状・原因・直し方の表で整理します。
この記事のポイント
- 末尾カンマ・コメント・全角引用符はJSONでは不可。空白は4種類だけ
- エラー位置は原因の直後を指す。位置番号は0から数える
- 壊れた箇所はJSONを整えるで行と列を日本語で確かめて直せる
- Q.
- JSONの最後の要素のあとにカンマがあるとエラーになるのはなぜですか?
- A.
- JSONの仕様(RFC 8259)では、カンマは要素と要素の区切りにだけ使い、最後の要素のあとには置けないと決まっているためです。JavaScriptのコードや一部の設定ファイルでは許されることがあり、その感覚でJSONを書くと失敗します。最後のカンマを消せば読み込めます。
JSONを読み込もうとして「Unexpected token」といったエラーが出る。見た目は正しそうなのに、どこが悪いのかわからない。そういうときに疑う場所は、ある程度決まっています。
結論を先に書きます。JSONが読み込めない原因で最も多いのは、最後の要素のあとのカンマ(末尾カンマ)と、半角のダブルクォート以外の引用符です。 コメントを書いたことも、よくある原因です。JSONの仕様であるRFC 8259には、末尾カンマにもコメントにも、書いてよいという規則がありません。この記事では、RFC 8259の規則と、Node.jsとPythonで実際に試した結果をもとに、エラー別のチェックリストを作りました。
JSONの規則は意外と少ない
JSONの文法は、RFC 8259(2017年12月)に定められています。関係する規則を先に整理します。
- 文字列とキー名は、半角のダブルクォート(“)で囲む
- 値として書けるのは、オブジェクト、配列、数値、文字列、そして true、false、null の3つのリテラルだけ
- true、false、null は小文字でなければならない
- 空白として許されるのは、スペース、タブ、改行(LF)、復帰(CR)の4種類だけ
- 区切りのカンマは、要素と要素の間にだけ置く
- コメントを書く規則は存在しない
- 1つのJSONテキストは1つの値で構成される
エラー別チェックリスト:12の原因
原因ごとに、壊れた例と直し方をまとめました。例は、Node.jsの JSON.parse で実際に確かめたものです。
| 番号 | 原因 | 壊れた例 | 直し方 |
|---|---|---|---|
| 1 | 末尾カンマ | {“a”:1,} や [1,2,] | 最後のカンマを消す |
| 2 | シングルクォート | {‘a’:1} | ダブルクォートにする |
| 3 | 全角・スマート引用符 | {“a”:1} | 半角のダブルクォートにする |
| 4 | キー名の引用符なし | {a:1} | “a” と囲む |
| 5 | コメント | {“a”:1 // メモ} | コメントを消す |
| 6 | 全角スペース | {“a”: 1}(値の前に全角スペース) | 半角スペースか、削除 |
| 7 | 数値の書式 | 01、+1、.5、0x10 | 1、1、0.5、16 と書く |
| 8 | NaN・Infinity | {“a”:NaN} | null にするか、文字列にする |
| 9 | リテラルの大文字 | True、None、undefined | true、null |
| 10 | 文字列内の生の改行・タブ | “x(改行)y” | \n や \t と書く |
| 11 | バックスラッシュ | “C:\Users” | “C:\Users” と書く |
| 12 | BOM・複数のJSON | 先頭にBOM、{…}{…} と連続 | BOMを外す、1つずつ読む |
末尾カンマとコメントは「使える環境がある」から混乱する
1と5は、JSONを手で書く人が最もよく踏む原因です。
JavaScriptのコードでは、配列やオブジェクトの最後にカンマを書いても構いません。設定ファイルにも、コメントや末尾カンマを許す独自の拡張(JSONCなど)を使うものがあります。そのため、ある環境で動いていたファイルが、別のプログラムではエラーになることがあります。
RFC 8259のJSONでは、どちらも認められません。Node.jsで {“a”:1,} を読み込むと、「位置7でダブルクォートで囲んだキー名が必要」という趣旨のエラーが出ます。位置7はカンマではなく、その次の閉じ括弧 } の場所です。つまり、エラー位置は原因の直後を指すことが多いのです。「次のキー名が来るはずなのに閉じ括弧が来た」と判断した場所が報告されるためです。エラーの位置を見たら、その直前の文字を疑ってみてください。なお、位置番号は1ではなく0から数えます。
引用符は「見た目が似ている別の文字」が混ざる
2と3は、コピーして貼り付けた文章で起きます。ワープロや、チャット画面、文章を整えるツールからJSONをコピーすると、半角のダブルクォート(“)が、カーブした引用符(“ ”)や全角の引用符に置き換わっていることがあります。見た目はほとんど同じで、目では見つかりません。
シングルクォート(‘)も同じです。Pythonの辞書を print した結果をそのまま貼ると、シングルクォートと True、None が混ざって、複数のエラーが同時に出ます。
6の全角スペースも、同じ「見た目が似ている文字」の問題です。JSONで空白として許されるのは先ほどの4種類だけで、全角スペースは含まれません。文字列の中に書いた全角スペースは問題ありませんが、値と値の間に紛れ込むとエラーになります。
数値は書き方に細かい決まりがある
7、8、9は、JavaScriptやPythonの感覚で書くと失敗する部分です。
- 先頭のゼロ: 01 のように、0のあとに数字を続けた数値は認められません。0 の次に数字が来る書き方は、仕様で禁じられています。郵便番号や電話番号のように先頭の0に意味がある値は、数値ではなく文字列として “0123” と書きます
- 先頭のプラス記号と、小数点で始まる数: +1 や .5 は認められません。0.5 のように、整数部を省略せずに書きます
- NaN と Infinity: 仕様に「表現できない数値(InfinityやNaNなど)は許されない」と書かれています。Node.jsでは読み込みに失敗します。ところが、Pythonの標準の json.loads は NaN をそのまま受け付けて、nan として読み込みました。処理系によって結果が違うので、null などに置き換えておくのが安全です
- true・false・null: 小文字のみです。Pythonの True や None、JavaScriptの undefined は、JSONのリテラルではありません
もう1つ、エラーにはならないのに値が変わる落とし穴があります。桁数の大きな数値です。RFC 8259は、数値の範囲や精度の上限を実装に任せています。多くのソフトが使う倍精度(IEEE 754 binary64)では、整数が正確に扱えるのは -9,007,199,254,740,991 から 9,007,199,254,740,991(2の53乗より1小さい数)までです。RFC 8259も、この範囲の整数は相互運用できる、と書いています。
Node.jsで {“id”:12345678901234567890} を読み込むと、id は 12345678901234567000 になります。20桁のIDを数値のまま扱うと、末尾の桁が失われます。長いIDや口座番号のような値は、文字列で書くのが確実です。
文字列の中身に関する注意
10と11は、文字列の中に特別な文字を直接書いたときの原因です。
仕様では、文字列の中に直接書いてはいけない文字が決まっています。ダブルクォート、バックスラッシュ、そして制御文字(U+0000からU+001Fまで)です。改行やタブは制御文字なので、文字列の中に生のまま入れるとエラーになります。改行は \n、タブは \t と書きます。Pythonでは「Invalid control character」と報告されました。
バックスラッシュは、エスケープの始まりを示す文字です。Windowsのファイルパス “C:\Users” をそのまま書くと、\U という存在しないエスケープになり、エラーです。バックスラッシュ自体を書くときは、2つ重ねて “C:\Users” とします。
BOMと、複数のJSONの連結
12は、データの作り方や保存の仕方に原因がある場合です。
BOM(バイトオーダーマーク) は、ファイルの先頭に付く目に見えない文字(U+FEFF)です。RFC 8259は、ネットワークで送るJSONにBOMを付けてはならないと定めています。一方で、読み込む側がBOMを無視してもよい、とも書いていて、扱いは実装次第です。Node.jsの JSON.parse では、BOMつきの文字列は「予期しないトークン」で失敗しました。保存し直したあとにエラーが出始めたら、BOMを疑います。
複数のJSONの連結 は、ログなどで見かけます。{“a”:1}{“b”:2} のように、値が連続したファイルを JSON.parse に渡すと、「JSONのあとに空白以外の文字がある」というエラーになります。1つのJSONテキストは1つの値で構成されるためです。
直し方の順番
次の順番で見ていくと、原因にたどり着きやすくなります。
- エラーに示された位置の、直前の文字を見る(位置は0から数える)
- カンマ、引用符、括弧の対応を確かめる
- 全角の文字(引用符、スペース、コロン)が混ざっていないか確かめる
- 文字列の中の改行、バックスラッシュ、先頭のゼロ、BOMを確かめる
目で探すのが難しいときは、道具に任せるほうが確実です。JSONを整える は、壊れたJSONの場所を、何行目の何が悪いかを日本語で示します。末尾カンマ、全角の引用符、全角スペース、コメント、シングルクォートといった、コピーで壊れるタイプの破損は、ワンクリックで直せます。整形や圧縮をしても、20桁のIDのような長い数値を丸めず、元の文字のまま保ちます。
出典
- RFC 8259「The JavaScript Object Notation (JSON) Data Interchange Format」(2017年12月)
- 本文のエラーメッセージと読み込みの結果は Node.js と Python(標準の json モジュール)で確かめたもので、文言は処理系やバージョンで異なります