末尾カンマが JSON を壊す理由
要点:末尾カンマは JavaScript のオブジェクトリテラルでは合法で、JSON では致命的です。正確なエラー、原因となる RFC 8259 の文法、実際に効く三つの修正を示します。

要点:JSON はどこでも末尾カンマを禁じます。パーサーが失敗したらフォーマッタで最後のカンマを削除し、JSON5 や JSONC はローカルの寛容なパースにだけ使い、他のシステムへは常に標準 JSON を出力しましょう。
文法がそう定めているからです。
{
"name": "demo",
"size": 12,
}
JSON.parse は Unexpected token } in JSON at position 34 を投げます。Node は別の言い回しをしますが、どのエンジンも同じ場所を指します。} の前のカンマです。
パーサーが実際に文句を言っていること
RFC 8259 のオブジェクト生成規則はこうです。
object = begin-object [ member *( value-separator member ) ] end-object
角括弧は任意、アスタリスクはゼロ回以上を意味します。平たく言えば、カンマはメンバーを区切り、最後のメンバーの直後には } が続きます。
ですからカンマの後、パーサーは次のメンバー名の準備ができています。} を読み、失敗します。配列も同じで、[1, 2, 3,] は ] で失敗します。
習慣はどこから来るか
JavaScript のオブジェクトリテラルは ES5 以降末尾カンマを許し、Python のリストや Go の複合リテラルも同様です。エディタが自動で付けます。そして誰かが .js ファイルからオブジェクトリテラルを .json ファイルにコピーし、ファイルがパースしなくなります。
もう一つの一般的な原因は手組みの JSON です。i <= length で回るループが最後の要素の後にカンマを残します。
三つの修正
カンマを削除する。 手編集ならこれで十分です。JSON フォーマッタに貼るとエラーが行と列付きで報告され、どれを削除すべきか正確に分かります。
JSON5 としてパースする。 上位集合は末尾カンマを受け入れ、ローカル設定なら問題ありません。別システムに送るものには問題があります。受信側は依然として拒否します。
文字列連結をやめる。 JSON.stringify、json.dumps、Jackson を使います。シリアライザは区切りを正しく扱い、同時にエスケープも解決します。
簡易監査リスト
| 場所 | 典型的な原因 |
|---|---|
| ループ連結 | i <= length が余分なカンマを一つ残す |
| コピー&ペースト | JS ファイルから持ち上げたオブジェクトリテラル |
| テンプレート | ハードコードされたカンマと、もう一つ追加するループ |
| 手編集 | 最後のフィールドを削除し、そのカンマを残した |
FAQ
末尾カンマが JavaScript では合法で JSON では違うのはなぜですか?
JavaScript のオブジェクトリテラルは ES5 以降許し、Python のリストや Go の複合リテラルも同様なので、習慣が JSON まで付いてきます。RFC 8259 はカンマをメンバー間だけに許し、最後のメンバーの直後には } か ] が続きます。.js ファイルからオブジェクトリテラルを .json にコピーするのが通常の原因です。
末尾カンマを受け入れるために JSON5 としてパースすべきですか?
ローカル設定に限ります。上位集合は末尾カンマを受け入れますが、別システムに送るものは厳格な JSON としてパースされ、依然失敗します。受信側の寛容さに頼るのではなく、出力境界で標準 JSON を生成してください。
末尾カンマエラーの後、まずどこを見るべきですか?
エラーメッセージの位置から始めます。通常 } か ] の前のカンマを指します。次に三つの通常の原因を確認します。i <= length で書いたループ、JS ファイルから貼ったオブジェクトリテラル、カンマをハードコードしループと併用するテンプレート。フォーマッタに貼ると正確な行と列が報告されます。