V8 Node v24.15.0, V8 13.6.233.17 上でパーサーを実行して確認しました。
Bad control character in string literal in JSON at position N (line L column C)
ドキュメント内のどこかの文字列に、生の制御文字が含まれています。多くは本物の改行で、ときにはタブです。JSONの文字列は、U+0020未満の文字をエスケープせずに含めることができません。改行は\n、タブは\tと書く必要があります。位置は、その問題の文字を指しています。
JSONを貼り付けて、壊れている箇所を正確に確認する
入力
貼り付けたものがブラウザの外に出ることはありません。 connect-src の許可リストにより、これは約束ではなくブラウザによる保証になっています。 自分で確かめる
実際の原因
どれが答えになることが多いか、その順に並べています。
-
01 複数行のテキストを文字列に直接貼り付けた
SQL、HTML、ログの抜粋、あるいは本物の改行を含むエラーメッセージなど。パーサーにとって、その改行は文字列の終わりです。
壊れる例
{ "query": "SELECT * FROM users" }動く例
{ "query": "SELECT *\nFROM users" } -
02 文字列連結で組み立てたJSON
ほぼすべての事例の根本原因がこれです。手で組み立てたJSONは、埋め込んだ値をエスケープしません。代わりにオブジェクトをシリアライズすれば、この問題は起こりようがありません。
壊れる例
const body = '{"note": "' + note + '"}';動く例
const body = JSON.stringify({ note }); -
03 コピー&ペーストで紛れ込んだタブ
タブは目に見えず、表計算ソフトやターミナルからコピーすると簡単に文字列に入り込みます。\tとしてエスケープするか、ドキュメントを組み立てる前に取り除いてください。
-
04 値の中にWindowsの改行コード
復帰(U+000D)も制御文字です。Windowsのファイルから読み取って文字列に埋め込んだテキストは、\nに加えて\rも一緒に持ち込みます。
ほかのランタイムでの同じ間違い
根本にある問題は同一で、違うのは文言だけです。同僚がこれらのどれかを報告してきたなら、見ているものはあなたと同じです。
| Python | Invalid control character at: line 1 column 8 (char 7) |
|---|---|
| Java (Jackson) | Illegal unquoted character ((CTRL-CHAR, code 10)): has to be escaped using backslash to be included in string value |
よくある質問
- どの文字をエスケープする必要がありますか?
- U+0000からU+001Fまでのすべてと、ダブルクォート、バックスラッシュです。JSONはバックスペース、フォームフィード、改行、復帰、タブに短いエスケープを定義しています。その範囲のそれ以外の文字には、\u0000のような\u形式が必要です。
- パーサー側で受け入れさせることはできますか?
- JacksonにはALLOW_UNESCAPED_CONTROL_CHARSがあり、同様のスイッチを持つパーサーもあります。ただしそれは問題を直すのではなく隠すだけで、ドキュメントはほかのすべての受け取り側にとって不正なままです。JSONを生成する側でエスケープしてください。