結論:このエラー、原因はだいたい3パターンしかない
SnowflakeでCOPY INTOやPARSE_JSONを叩いたら、いきなり Error parsing JSON で落ちた。検索でここに辿り着いたなら、まず安心してください。このエラー、実際に手を動かして踏むと分かるのですが、原因は次の3つにほぼ集約されます。
- ファイルの中身がJSON配列(
[ {...}, {...} ])で、Snowflake側がそれを1レコードとして読もうとしている - NDJSON(改行区切りJSON)なのに、ファイルフォーマットでJSONを指定していない、もしくはCSV扱いされている
- JSON自体が壊れている(末尾カンマ、シングルクォート、BOM、改行コード混入など)
このうち、業務でロードを組んでいて一番頻発するのは断トツで1番。先に答えだけ書いておくと、STRIP_OUTER_ARRAY = TRUE を付ければ大半は通ります。ただ、それで黙らせて終わりにすると後で別の現象で詰むので、ちゃんと中身を確認しておきましょう。

再現コードとエラー原文
まずは、よくある詰まり方を再現してみます。S3やステージに置いたJSONファイルが、こういう形だったとします。
[
{"id": 1, "name": "alice"},
{"id": 2, "name": "bob"},
{"id": 3, "name": "carol"}
]
これを素直にロードしようとして、こう書いたとします。
CREATE OR REPLACE FILE FORMAT my_json_fmt
TYPE = JSON;
COPY INTO raw_users
FROM @my_stage/users.json
FILE_FORMAT = (FORMAT_NAME = my_json_fmt);
ところが返ってくるのは、こんなメッセージです。
Error parsing JSON: document is too large, max size 16777216 bytes
あるいは形式違いだとこちらが出ます。
Error parsing JSON: more than one document in the input
このエラー文をそのままGoogleに貼り付けてここに辿り着いた方、たぶん上のどちらかですよね。ちなみにSnowsightのエラー表示、テーブル名やステージ名が問答無用で大文字に化けて返ってくるので、自分の小文字定義と見比べてビクッとしますが、それは別の話です。
原因:Snowflakeは「1ファイル=1ドキュメント」とは限らないと考える
JSONのロード挙動を理解するうえで一番大事なのは、SnowflakeのTYPE = JSONはNDJSON(=1行1JSONオブジェクト)を前提に動くという点です。つまり、こういう形が一番きれいに通ります。
{"id": 1, "name": "alice"}
{"id": 2, "name": "bob"}
{"id": 3, "name": "carol"}
ところが世の中のAPIは、ほぼ確実に外側を [ ... ] でくくった「単一の配列」で返してきます。Snowflakeは配列全体を1ドキュメントとして読もうとして、要素数が多いと document is too large、複数の配列が並んでいると more than one document を吐く、という構造です。
そして、これを解決するために用意されているのが STRIP_OUTER_ARRAY オプションです。これをTRUEにすると、ロード時に外側の[ ]を剥がし、内側の各要素を別レコードとしてVARIANTカラムへ展開してくれます。
原因切り分けチェックリスト
解決SQLに行く前に、自分のケースがどれに該当するか、ざっとチェックしましょう。
- ファイルが
[で始まっているか? → ローカルでhead -c 200 file.json。先頭が[なら配列形式、{ならオブジェクト形式。 - 1行に複数のJSONが連結されていないか? → APIのレスポンスを単純連結したログでよくあります。
- BOM()が混入していないか? → Windowsで保存したUTF-8 JSONあるある。
fileコマンドで確認できます。 - 末尾カンマ、シングルクォート、コメント行 → JSON5やJSONCの記法は通りません。標準JSONに整形する必要があります。
- ファイル全体のサイズが16MBを超えていないか? → 単一ドキュメントとして読まれた場合の上限です。
STRIP_OUTER_ARRAY適用後の各要素サイズでも16MBを超えると同じエラーが出ます。

解決方法:パターン別の修正SQL
パターン1: 外側が配列のJSON → STRIP_OUTER_ARRAYを足す
一番多いやつです。ファイルフォーマットを作り直すか、COPY INTO側でその場指定でも構いません。
CREATE OR REPLACE FILE FORMAT my_json_fmt
TYPE = JSON
STRIP_OUTER_ARRAY = TRUE;
COPY INTO raw_users
FROM @my_stage/users.json
FILE_FORMAT = (FORMAT_NAME = my_json_fmt);
これで配列内の{"id":1,...}がそれぞれ1レコードになって入ります。VARIANTカラムはraw_users(v VARIANT)のような1列構成にしておくのが定番です。
パターン2: ロード前に内容を確認したい
本番ロード前に一回中身を覗きたい時は、SELECTでステージから直接読めます。これ、地味に便利です。
SELECT $1
FROM @my_stage/users.json
(FILE_FORMAT => 'my_json_fmt')
LIMIT 5;
ここで$1に配列丸ごとが入ってきたら、配列形式確定。STRIP_OUTER_ARRAY = TRUEを付けて再実行すると、要素単位に変わるのが確認できます。
パターン3: PARSE_JSON側でこけている場合
ロードではなく、すでにVARCHARで取り込んでしまった文字列に対して PARSE_JSON をかけたら落ちる、というケース。これはJSON自体が壊れているか、エスケープ漏れの可能性が高いです。TRY_PARSE_JSONに置き換えれば、失敗時にNULLを返すだけになるので、まずどのレコードで落ちているか特定できます。
SELECT id, raw_text
FROM staging_logs
WHERE TRY_PARSE_JSON(raw_text) IS NULL
AND raw_text IS NOT NULL
LIMIT 100;
引っかかったレコードを目視で見ると、末尾カンマやNaNといったJSON標準外のリテラルが混ざっていることが多いはずです。
パターン4: 1ファイル内にJSONがダラダラ連結されている
APIレスポンスをそのままcatで結合した、みたいなファイルだと more than one document が出ます。これはENABLE_OCTAL = FALSEとか別オプションでは救えません。素直にNDJSON形式(1行1オブジェクト)に整形し直すのが最短です。ロード前処理がない環境なら、SnowflakeのTask + ストアドプロシージャで前処理を挟む手もあります。
Snowsightでの確認手順
Snowsightからやる場合、左メニューの「Data」→「Databases」から該当ステージを開き、「Load Data」ウィザードに進むとファイルフォーマットを画面から設定できます。Strip outer arrayのチェックボックスがそのまま出ているので、初手はここをオンにして試すのが早いです。ちなみに、ウィザードで作ったファイルフォーマットはそのままオブジェクトとして残るので、SHOW FILE FORMATS;で名前を確認して、以降のスクリプトから参照すると運用が楽になります。
余談ですが、Snowsightのワークシートはしばらく放置すると裏でセッションが切れていて、ウィザードから戻った瞬間にUSE WAREHOUSEが外れていることがあります。ロード前にSELECT CURRENT_WAREHOUSE();を一回叩く癖をつけておくと、変なところで詰まらずに済みます。

再発防止の運用Tips
一度直っても、次のファイルでまた踏むのがこのエラーの厄介なところです。実務で長くSnowflakeを触っていると、次の運用が効いてきます。
- ファイルフォーマットは「配列前提」と「NDJSON前提」を2種類用意して命名で分ける。例えば
JSON_ARRAY_FMTとJSON_NDJSON_FMTのように。命名規則についてはSnowflake命名規則ベストプラクティスもあわせて参考にしてください。 - COPY INTOには必ず
ON_ERROR = 'CONTINUE'か'SKIP_FILE'を一旦付けて検証する。1件目で全停止すると残り何件壊れているか永遠に分かりません。詳しくはCOPY INTO失敗のチェックリストを参照ください。 - VALIDATION_MODE = RETURN_ERRORSでドライランしておくと、本番ロードの前にエラー行が一覧で返ってきます。
- VARIANTカラムへ取り込んだ後の型変換は
TRY_*系で書く。TRY_TO_NUMBERやTRY_TO_DATEを活用すると、後段の集計でこける確率が下がります。
まとめ
Error parsing JSONが出たら、まずはファイルの先頭1文字を確認。[で始まっていたらSTRIP_OUTER_ARRAY = TRUE、それでもダメならファイルそのものが壊れていないか、NDJSON形式に整形できないかを順に潰していく――この順番だけ覚えておけば、検索画面に戻る回数はぐっと減るはずです。
VARIANT周りはSnowflakeの強みでもあり、最初のロード段階でつまずきやすいポイントでもあります。一度フォーマット定義をきれいに揃えておくと、次回からは「ステージにファイルを置いてCOPY INTOを叩くだけ」の世界に持っていけます。
参考リンク
- CREATE FILE FORMAT(Snowflake公式ドキュメント)
- 半構造化データのロード時の考慮事項
- PARSE_JSON / TRY_PARSE_JSON
- COPY INTO <table>
関連記事
- SnowflakeでCOPY INTOが失敗する原因と解決方法|エラー別チェックリスト – JSON以外も含めたロード全般のエラー切り分けに。
- Snowflake「Numeric value is not recognized」エラーを解決!数値変換の正しい使い方 – VARIANT展開後の数値キャストで詰まったらこちら。
- Snowflake「Date is not recognized」エラーの原因とTO_DATE/TRY_TO_DATEの使い分け – 日付フィールドの型変換で同じ系統のエラーが出た時に。
- Snowflake「Failed to access remote file」エラーの原因と解決方法 – そもそもステージのファイルが読めない時はこちらから。
- Snowflake「Duplicate row detected」エラーの原因とMERGE文での対処方法 – 関連するエラー対処の手順をまとめています


