← 記事一覧

"[object Object] is Not Valid JSON" などの JSON 構文エラーを直す

"[object Object] is not valid JSON" や "expected a JSON object, array or literal" が出る? 原因、JSON 構文の正しい修正、末尾カンマの修正、壊れた JSON の自動修復を学ぶ。

コードを実行し、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 は小文字:nullNone nilNULL ではない。
  • undefined は不可。 JSON に undefined 型はない。 null を使うか、キーを完全に省略する。
  • NaNInfinity も不可。 これらの JavaScript 値は JSON で表現できない。JSON.stringify({x: Infinity}) は静かに {"x":null} を生む。

余分なコンテンツ

  • コメントは不可。// 行コメント /* ブロックコメント */ は JSON 仕様の一部ではない。
  • 末尾の余計なコンテンツも不可。 有効な JSON テキストはちょうど 1 つの値 —— 先頭には任意の空白以外何もなく、末尾にも何も置けない。

JSON 修正器を使う: いつ自動化するか

単発のデバッグなら手動で直すのが速いです。しかし外部ソース(API、AI モデル出力、ユーザー入力)から JSON を受け取る本番パイプラインには、JSON 修正器 が必要です: 妥当な内容を壊さず一般的な構文エラーをプログラム的に修復するコードかツールです。

良い JSON 修正器は次を扱います:

  • オブジェクトと配列の末尾カンマ
  • シングルクオート文字列 → ダブルクオート文字列
  • 引用符なしのキー → ダブルクオートのキー
  • Python リテラル(TrueFalseNone)→ 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 / Infinitynull に変えます。これらは 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.okContent-Type ヘッダを確認してください。

もっとも多い JSON 構文エラーは?

末尾カンマ、シングルクオート、引用符なしキー、Python リテラル(True/None)、コメント、NaN/Infinity。それぞれに専用ガイドがあります: 末尾カンマunexpected-token エラーunexpected end of input、そして 不正な制御文字

JSON 構文をオンラインで直す —— セットアップ不要

今すぐ修正したい壊れた JSON 文字列があれば、JSON Fix が上記すべてのエラーを自動で修復します。どんなに壊れていても JSON を貼り付け、Repair & Format をクリックすれば、構文的に正しく整形された JSON が返ってきます。ツールは完全にブラウザ内で動き、データはどのサーバーにも送られません。機微なペイロードでも安全です。