SyntaxError: Unexpected token o in JSON at position 1 —— その小文字の o は [object Object] の 2 文字目です。これは JavaScript オブジェクトを JSON 文字列ではなく直接 JSON.parse() に渡してしまったことを意味します。本記事ではこのエラーのあらゆるバリエーションと、1 分以内にそれぞれを修正する方法を解説します。
なぜエラーが「token o」と言うのか
文字列ではない値を JSON.parse() に渡すと、JavaScript はまずそれを文字列に強制変換します。プレーンなオブジェクトは "[object Object]" になります。パーサは位置 0 の [(有効 —— 配列の開始)を読み取り、次に位置 1 の o(無効 —— 有効な配列要素ではない)に出会います。だから:Unexpected token o at position 1。
JSON.parse({})
// 同じこと: JSON.parse("[object Object]")
// SyntaxError: Unexpected token o in JSON at position 1最も一般的な原因:response.json() を await していない
実際のコードベースでこのエラーが起きる最大の原因です。fetch() の Response オブジェクトは文字列ではなく、ReadableStream のラッパーです。これを JSON.parse() に渡すと "[object Response]" に強制変換されます。
// ❌ 誤り —— response は Response オブジェクトであり文字列ではない
const response = await fetch('/api/user');
const data = JSON.parse(response);
// SyntaxError: Unexpected token o in JSON at position 1
// ✓ 正しい —— ブラウザにストリームを JSON としてパースさせる
const data = await response.json();同様に、response.text() を await なしで呼ぶと、Promise オブジェクトが返ります(これは "[object Promise]" に強制変換されます)。
// ❌ await 漏れ —— text は Promise であり文字列ではない
const text = response.text();
const data = JSON.parse(text);
// SyntaxError: Unexpected token o in JSON at position 1
// ✓ 正しい
const text = await response.text();
const data = JSON.parse(text);このエラーを引き起こす他のオブジェクト
| 渡したもの | JS が強制変換する文字列 | エラーのトークン |
|---|---|---|
{} または任意のプレーンオブジェクト | "[object Object]" | 位置 1 の token o |
undefined | "undefined" | 位置 0 の token u |
true / false | "true" / "false" —— 実は有効な JSON! | エラーなし |
Response オブジェクト | "[object Response]" | 位置 1 の token o |
Promise | "[object Promise]" | 位置 1 の token o |
null | "null" —— 有効な JSON | エラーなし(null を返す) |
原因:シリアライズせずにオブジェクトを渡している
関連する間違い:すでにメモリ上にある JavaScript オブジェクトを「パース」しようとすること。JSON.parse() は 文字列 を受け取ります。すでにオブジェクトを持っているなら、パースする必要はまったくありません。
const config = { host: 'localhost', port: 3000 };
// ❌ 無意味 —— config はすでにオブジェクト
const parsed = JSON.parse(config);
// ✓ ディープクローンが欲しいなら structuredClone か stringify + parse
const clone = JSON.parse(JSON.stringify(config));
// ✓ 送信したいなら JSON.stringify
const body = JSON.stringify(config);原因:Python など他のバックエンドが間違った Content-Type を返している
サーバが "ok" や "not found" のようなプレーンテキストのエラーメッセージを、200 ステータスかつ Content-Type ヘッダなしで返してくることがあります。フロントエンドは JSON と仮定して response.json() を呼び、ボディが有効な JSON ではないため unexpected token エラーが発生します。
// サーバが送るリテラル文字列: ok
// ブラウザがそれを JSON としてパースしようとする:
JSON.parse("ok")
// SyntaxError: Unexpected token o in JSON at position 0修正: response.json() を呼ぶ前に必ず response.ok と response.headers.get('Content-Type') をチェックします:
const response = await fetch('/api/action');
if (!response.ok) {
const text = await response.text(); // 安全 —— JSON でない可能性がある
throw new Error(`HTTP ${response.status}: ${text}`);
}
const data = await response.json();あまり見ない [object X] のバリエーション
toString() が [object で始まる文字列を返す値はすべて、位置 1 で同じエラーを起こします。[object Object] 以外で、実際のコードで遭遇するものは次のとおりです:
[object Module]—— 動的インポートの結果を渡している場合:const mod = await import('./data.json', { with: { type: 'json' } })。欲しいのはmod.defaultであってmodではありません。[object AsyncFunction]—— 非同期関数の参照を渡しており、呼び出して いない場合:fnではなくfn()(Promise の解決値)を文字列化します。[object HTMLDocument]——documentを誤って渡している(例: 古いデバッガのスニペットから)。[object FormData]——fetch(url, { body: formData })は問題ありませんが、JSON.parse(formData)はダメです。まずObject.fromEntries(formData)で変換してください。
クイック修正チェックリスト
- fetch + JSON.parse?
await response.json()に置き換えましょう。 - 途中で await が漏れていないか? パースの前にある
asyncな呼び出しはすべて await が必要です。 - すでにオブジェクト? パースは不要です。そのまま使うか、
structuredClone()でクローンしてください。 - エラー時にサーバが JSON 以外を返す? 応答が JSON でない可能性があるときは
response.text()で読み取り、response.json()は使わないでください。
よくある質問
「Unexpected token o in JSON at position 1」とはどういう意味?
JavaScript オブジェクトを JSON.parse() に渡しています。JavaScript はオブジェクトを文字列 "[object Object]" に強制変換し、パーサは位置 0 の [ は受け入れますが、位置 1 の o を拒否します。
fetch ではどう修正する?
JSON.parse(response) を呼ばないこと。代わりに await response.json() を使い、レスポンスストリームを読み取って自動的にパースします。チェーンの各ステップが await されていることを確認してください。
すでにオブジェクトがあるなら JSON.parse は必要?
いいえ。JSON.parse() は JSON 文字列 を値に変換するだけです。すでにオブジェクトを持っているならそのまま使うか、JSON.parse(JSON.stringify(obj)) の代わりに structuredClone() でディープクローンしてください。
「Unexpected token o」と「[object Object] is not valid JSON」は同じもの?
根本原因は同じ —— パース前にオブジェクトが文字列化されたことです。新しい V8 ビルドは [object Object] is not valid JSON という文言で出力し、古いビルドは Unexpected token o と出力します。詳細は 「[object Object] is not valid JSON」を修正する を参照 してください。
生のレスポンスを確認する
API が実際に何を返しているか不明な場合は、生のボディを JSON Fix に貼り付けて検証してください。有効な JSON でなければ、何が間違っているかをバリデータが正確に教えてくれます。
- JSON Fix —— ブラウザ内で JSON を検証・修復
- 「[object Object] is not valid JSON」を修正する —— JSON 構文エラー完全ガイド
- Unexpected end of JSON input —— 構造が完成する前に入力が尽きた場合
- JavaScript で壊れた JSON を扱う —— 安全なパースパターンとエラーリカバリ