本文へ移動
verified onnext@16.3.5react@19
最終検証日 2026-09-26
Next.js道場

Only plain objects の直し方

実際に出るエラー

Error: Only plain objects, and a few built-ins, can be passed to Client Components
from Server Components. Classes or null prototypes are not supported.

クラスのインスタンスを Server Component から Client Component へ渡したときに出るエラーです。

何が起きているか

境界を越えられる値・越えられない値
渡すもの越えられるか備考
文字列 / 数値 / 配列 / オブジェクトできる中身も再帰的に見られる
Date / Map / SetできるJSON とは違い型のまま渡る
クラスのインスタンスできないこのエラーの原因
プロトタイプが null のオブジェクトできない文言にも書かれている
関数できない別のエラーになる

Server Component から Client Component へ渡す props は、値だけがネットワークを越えます。

クラスのインスタンスは、値のほかにプロトタイプ(メソッドの置き場)を持っています。値だけを運ぶと、メソッドが消えた別物になってしまう。React はそういう「一部だけ壊れた値」を作らず、境界で止めます。

境界を越えられる値・越えられない値
渡すもの越えられるか備考
文字列・数値・真偽値できるそのまま
配列・プレーンなオブジェクトできる中身も再帰的に見られる
Date・Map・SetできるJSON とは違い型のまま渡る
BigInt・TypedArrayできるそのまま
Server Component の要素できるchildren として渡す形
関数できない別のエラーになる
クラスのインスタンスできないこのエラーの原因
SymbolできないSymbol.for で作ったものは渡せる
プロトタイプが null のオブジェクトできない文言にも書かれている

Date や Map は渡せます。JSON にできるかどうかは基準ではありません。基準は「実行できる形を持っているか」です。

原因はほぼこの3つ

1. ORM が返したオブジェクトをそのまま渡している

いちばん多い形です。ORM によっては、行を単なるオブジェクトではなくモデルのインスタンスとして返します。

const user = await db.user.findFirst()
return <Profile user={user} />   // ← user がインスタンスだと止まる

2. 自作のクラスを渡している

Money、DateRange、Result のような値オブジェクトです。

3. ライブラリの戻り値を渡している

Decimal、Big.js、Temporal のポリフィル、独自の Error サブクラスなどが該当します。

最短の確認手順

エラー文には、止まった props の中身が出ます。まずそれを読んでください。それでも分からないときは、渡す直前でこう確かめます。

console.log(Object.getPrototypeOf(value) === Object.prototype)
// false ならプレーンなオブジェクトではない

直し方

必要な値だけを組み立てて渡す
うまくいかない
const price = new Money(1200)
 
return <View price={price} />

クラスのインスタンスをそのまま渡している。

こう書く
const price = new Money(1200)
 
return <View yen={price.yen} label={price.format()} />

表示に要る値だけを取り出す。整形もサーバー側で済ませられる。

推奨:必要な値だけを取り出して渡す

const row = await db.user.findFirst()
 
const user = {
  id: row.id,
  name: row.name,
  joinedAt: row.joinedAt,   // Date はそのままでよい
}
 
return <Profile user={user} />

これには副次的な効果があります。渡した props はすべてブラウザに届くので、必要な列だけに絞ることは、そのまま「余計なデータを送らない」ことになります。パスワードのハッシュや内部フラグを含む行を丸ごと渡してしまう事故も防げます。

境界を引き直す

そもそも Client Component である必要がないなら、'use client' を外すのがいちばん簡単です。境界を越えなければ、インスタンスのまま扱えます。

やってはいけない直し方:JSON で往復させる

<Profile user={JSON.parse(JSON.stringify(row))} />

エラーは消えますが、

  • Date が文字列に変わる(受け取る側で壊れる)
  • undefined のキーが消える
  • 送りたくない列まで一緒に送ってしまう

ので、直したことになりません。必要な値を明示的に選ぶほうが、短く書けて安全です。

なぜ開発中に気づきにくいのか

このエラーは描画のときに出ます。prerender される構成ならビルド中に失敗するので気づけますが、リクエストごとに描画される構成では、そのページを開くまで出ません。

さらに、データの中身によって出たり出なかったりします。findFirst() が null を返す経路しか通っていないと、開発中は一度も出ないことがあります。

再発防止

  • Server Component から Client Component へ渡す形を、明示的に組み立てると決めておく
  • ORM の行をそのまま渡さない
  • 渡す props の型を、プレーンな形で先に定義しておく

関連するエラー

関数を渡した場合は文言が変わります。

Event handlers cannot be passed to Client Component props.

原因は同じ「境界を越えられないものを渡した」で、種類が違うだけです。

出典

このページの内容は上記の一次情報を基準に書いています。個人ブログや二次情報を根拠にしていません。

理解できたか試す

では、このコードはどうなりますか。

Money はメソッドを持つクラスです。このコードはどうなりますか。

この問題を解くこのテーマの問題 3 問