コードを実行し、Network タブを確認すると、これが見えます: "[object Object]" is not
valid JSON。あるいは JSON バリデータが Expected a JSON object, array or literal と言う、あるいはパーサーが最後の要素の後のカンマで詰まる。これらは開発者が遭遇するなかでもっとも一般的で、そして混乱しがちな JSON ミスです。本ガイドはそれぞれのエラーが何を意味し、なぜ起きるのか、そしてパーサーに受理させるためにどう JSON 構文を直すかを正確に説明します。
「[object Object] is not valid JSON」とは何を意味するか
JavaScript が JSON.stringify() を使わずにオブジェクトを文字列に変換すると、結果はテキスト [object Object] になります —— これはすべてのオブジェクトの .toString() メソッドの既定出力です。その文字列が次に JSON.parse() に渡されたり、リクエストボディとして送信されたりすると、次のエラーが出ます:
SyntaxError: "[object Object]" is not valid JSONパーサーはリテラルテキスト [object Object] をパースしようとしています。[ を見て JSON 配列を期待し、引用符なしの語 object を見つけて失敗します。角括弧は本物 —— それは文字列 [object Object] の最初の文字 —— ですが、続く内容は有効な JSON 配列の構文ではありません。
なぜ JSON に [object Object] が現れるのか
根本原因は常に同じ: パースまたは送信の前に、コードのどこかで JavaScript オブジェクトが文字列へ強制変換されたからです。もっとも多い 4 つのパターン:
文字列連結
オブジェクトを文字列と連結すると、JavaScript はオブジェクトの .toString() を呼びます。それは [object Object] を返します:
const user = { name: "Alice", age: 30 };
// ❌ 文字列連結でオブジェクトが強制変換される
const body = "data=" + user;
console.log(body); // "data=[object Object]"
// ✅ JSON.stringify を使う
const body = "data=" + JSON.stringify(user);fetch / XMLHttpRequest のボディに JSON.stringify を使わない
プレーンなオブジェクトを fetch 呼び出しの body として渡すと、自動的に文字列へ変換されます:
const payload = { action: "login", user: "alice" };
// ❌ fetch がオブジェクトを "[object Object]" に強制変換
fetch('/api/login', {
method: 'POST',
body: payload,
});
// ✅ 先に直列化し、Content-Type を設定
fetch('/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
});テンプレートリテラル
オブジェクトをテンプレートリテラルに直接埋め込むと .toString() が呼ばれます:
const config = { theme: "dark", lang: "en" };
// ❌ テンプレートリテラルでの強制変換
const json = `{"config": ${config}}`;
// '{"config": [object Object]}' ← 無効な JSON
// ✅ オブジェクトだけ stringify する
const json = `{"config": ${JSON.stringify(config)}}`;
// '{"config": {"theme":"dark","lang":"en"}}'入れ子の stringify
値としてすでに直列化済みの JSON 文字列を持つオブジェクトに JSON.stringify() を呼ぶと、二重エンコードされた出力が出ます —— JSON 内に表れるのは文字列リテラルであり、それが表すオブジェクトではありません:
const inner = JSON.stringify({ id: 1 }); // '{"id":1}'
const outer = JSON.stringify({ data: inner });
// '{"data":"{\"id\":1}"}' — data フィールドは文字列であって、オブジェクトではない
// あとで外側の文字列を JSON.parse() し、再度 data を JSON として使うなら、
// もう一度 JSON.parse(result.data) する必要があります。[object Object] JSON エラーの直し方
解決策は常に同じ: オブジェクトを文字列として使うか、ネットワーク越しに送信するより前に JSON.stringify() で直列化するのを徹底すること。手早い診断: 対象の変数が文字列として使われる場所をコード全体で探し、そこに JSON.stringify() を加えます。
// 体系的な修復パターン
function toJsonBody(obj) {
if (typeof obj === 'string') {
// すでに文字列 —— 使う前に有効な JSON かを検証
JSON.parse(obj); // 無効なら投げる
return obj;
}
return JSON.stringify(obj);
}「Expected a JSON Object, Array or Literal」の意味
このエラーは Firefox 組み込みの JSON ビューワー(および一部の JSON バリデータ)が出すもので、トップレベルの値が 6 つの有効な JSON 型のいずれでもないことを意味します。よくある原因:
- 入力が空文字列。
JSON.parse("")は空文字列が有効な JSON 値ではないためこのエラーを投げます。 - 入力が
undefined。JSON.stringify(undefined)はundefinedを返し(文字列"undefined"ではない)、JSON.parse(undefined)は例外を投げます。 - レスポンスが JSON ではなく HTML。 サーバーエラーページはしばしば HTML を返します。最初の文字
<は有効な JSON ではありません。JSON 本体が壊れていると決めつける前に、Network タブのContent-Typeヘッダと素のレスポンスボディを確認してください。 - ファイル先頭の BOM。 JSON ファイル先頭に付いた UTF-8 BOM(バイト
0xEF 0xBB 0xBF)は厳格なパーサーでこのエラーを起こします。RFC 8259 は JSON における BOM を明示的に禁止しています。
// 空 / undefined をパース前にガード
function safeParse(text) {
if (!text || typeof text !== 'string') {
throw new TypeError(`Cannot parse ${typeof text} as JSON`);
}
return JSON.parse(text.trimStart()); // trimStart で偶発的な BOM/空白を除去
}JSON で最後の要素の後にカンマを置く: 末尾カンマエラー
もう一つ非常に多い JSON 構文エラーが末尾カンマ —— オブジェクトや配列の最後の項目の後に現れるカンマです:
// ❌ オブジェクトの末尾カンマ
{
"name": "Alice",
"age": 30,
}
// ❌ 配列の末尾カンマ
["red", "green", "blue",]JSON の文法は、カンマは 2 つの要素を区切るものと定めており、両側に値が必要です。後ろに何もないカンマは文法違反です。JavaScript 自体は(ES5 以降)末尾カンマを許可しており、それが開発者がついうっかり書いてしまう理由です。
末尾カンマをプログラムで見つけて直すには:
// ⚠️ 正規表現での修正 —— 単純なケースで動くが、文字列を破壊しうる
const fixed = raw.replace(/,\s*([}\]])/g, '$1');
// ✅ より良い: 文法を理解する修復パーサーを使う
// 例えば npm の json-repair ライブラリこの具体的なエラーの詳細は JSON の末尾カンマ: なぜ例外を投げるか、どう直すか を参照。
JSON 構文を直す: 完全チェックリスト
JSON 修正ツールに手を伸ばす前に、このチェックリストでエラーの分類を特定しましょう:
構造
- すべての
{に対応する}がある 、すべての[に対応する]がある。閉じていない括弧はもっとも多い切り捨て型エラーの一つです。 - 末尾カンマなし —— オブジェクトの最後のキー値ペアや配列の最後の項目の後にカンマを置かない。
- カンマの欠落なし —— オブジェクトや配列の項目は(最後を除き)後ろにカンマが必要。
文字列
- すべての文字列はダブルクオート。 シングルクオートの文字列(
'Alice')は JavaScript の構文であって JSON ではない。 - すべてのオブジェクトキーはダブルクオート文字列。 裸のキー(
{ name: "Alice" })は JavaScript のオブジェクトリテラル構文であって JSON ではない。 - 文字列内の制御文字はエスケープ。 JSON 文字列内の生の改行、タブ、ヌルバイトは違法 ——
\n、\t、\u0000などを使う。
値
- ブール値は小文字:
true/false、True/False/TRUEではない。 - Null は小文字:
null、None、nil、NULLではない。 undefinedは不可。 JSON に undefined 型はない。nullを使うか、キーを完全に省略する。NaNもInfinityも不可。 これらの JavaScript 値は JSON で表現できない。JSON.stringify({x: Infinity})は静かに{"x":null}を生む。
余分なコンテンツ
- コメントは不可。
// 行コメントと/* ブロックコメント */は JSON 仕様の一部ではない。 - 末尾の余計なコンテンツも不可。 有効な JSON テキストはちょうど 1 つの値 —— 先頭には任意の空白以外何もなく、末尾にも何も置けない。
JSON 修正器を使う: いつ自動化するか
単発のデバッグなら手動で直すのが速いです。しかし外部ソース(API、AI モデル出力、ユーザー入力)から JSON を受け取る本番パイプラインには、JSON 修正器 が必要です: 妥 当な内容を壊さず一般的な構文エラーをプログラム的に修復するコードかツールです。
良い JSON 修正器は次を扱います:
- オブジェクトと配列の末尾カンマ
- シングルクオート文字列 → ダブルクオート文字列
- 引用符なしのキー → ダブルクオートのキー
- Python リテラル(
True、False、None)→ JSON 相当の値 - JavaScript の
// 行と/* ブロック */コメント → 削除 - Markdown のコードフェンス(
```json ... ```)→ 除去 - 閉じていない括弧 → 自動で閉じる
肝心なのは修正が文法を理解していること —— どのトークンが構造の区切りでどれが文字列値の内側かを把握し、たまたま ,} や True を含む文字列内容を壊さないことです。
JavaScript で JSON 修復を実装するウォークスルーは JavaScript で壊れた JSON を扱う方法 を参照。
JSON.stringify の落とし穴を避ける(循環参照を含む)
常に JSON.stringify で直列化する習慣がついても、まだ二つの状況で躓きます:
- 循環参照は例外を投げる。
const a = {}; a.self = a;のような値はTypeError: Converting circular structure to JSONになります。良い代替が三つ: 既出オブジェクトを追跡するカスタムreplacerで逆参照を落とす; インメモリのディープコピーにはstructuredClone(value)に切り替える; 循環グラフを真に直列化して後で復元したいならflattedのようなライブラリを使う。 - 情報を失う型。
JSON.stringifyは 静かにundefined、関数、Symbol値を落とし、NaN/Infinityをnullに変えます。これらは stringify の前 に表現可能なものへ変換すべきで、パース後ではありません。
クイックリファレンス: よくある JSON エラーと修正
// 1. [object Object] — オブジェクトが文字列に強制変換
❌ fetch(url, { body: myObject })
✅ fetch(url, { body: JSON.stringify(myObject) })
// 2. 末尾カンマ
❌ { "a": 1, "b": 2, }
✅ { "a": 1, "b": 2 }
// 3. シングルクオート
❌ { 'name': 'Alice' }
✅ { "name": "Alice" }
// 4. 引用符なしのキー
❌ { name: "Alice" }
✅ { "name": "Alice" }
// 5. Python のブール
❌ { "active": True }
✅ { "active": true }
// 6. JSON 内のコメント
❌ { "debug": true // log everything }
✅ { "debug": true }
// 7. 空文字列
❌ JSON.parse("")
✅ JSON.parse(text || "null")
// 8. 「JSON」として HTML エラーページ
❌ JSON.parse("<!DOCTYPE html>...")
✅ response.json() を呼ぶ前に response.ok と Content-Type を確認よくある質問
「[object Object] is not valid JSON」とは?
JavaScript オブジェクトが既定の .toString() で文字列化されてリテラル [object Object] が生まれ、そのテキストがその後 JSON としてパース・送信されました。直し方は、値を文字列として使う前に JSON.stringify() で直列化すること。
fetch リクエストでの [object Object] エラーの直し方は?
body: JSON.stringify(payload) を設定し、Content-Type: application/json ヘッダを付ける。生のオブジェクトをそのまま body に渡すと [object Object] に強制変換されます。
「Expected a JSON object, array or literal」とは?
トップレベルの値が 6 種の JSON 型のいずれでもないときに Firefox や一部のバリデータが出すメッセージ —— 通常、入力が空、undefined、JSON ではなく HTML、あるいはバイトオーダーマークで始まっています。まず response.ok と Content-Type ヘッダを確認してください。
もっとも多い JSON 構文エラーは?
末尾カンマ、シングルクオート、引用符なしキー、Python リテラル(True/None)、コメント、NaN/Infinity。それぞれに専用ガイドがあります: 末尾カンマ、unexpected-token エラー、unexpected end of input、そして 不正な制御文字。
JSON 構文をオンラインで直す —— セットアップ不要
今すぐ修正したい壊れた JSON 文字列があれば、JSON Fix が上記すべてのエラーを自動で修復します。どんなに壊れていても JSON を貼り付け、Repair & Format をクリックすれば、構文的に正しく整形された JSON が返ってきます。ツールは完全にブラウザ内で動き、データはどのサーバーにも送られません。機微なペイロードでも安全です。
- JSON Fix — 壊れた JSON を即座に修復・整形
- JavaScript で壊れた JSON を扱う方法 — 自分のアプリケーションコードに堅牢な JSON 修復を組み込む
- Unexpected Token o in JSON at Position 1 — [object Object] エラーの近縁
- JSON とは — JSON のフォーマット、構文、データ型の完全ガイド
- JSON Diff — 元の JSON と修正後の JSON を比較して、修正が正確か確認