Error: Only plain objects, and a few built-ins, can be passed to Server Actions. Classes or null prototypes are not supported.
ID: nextjs/server-action-serialization-error
Version Compatibility
| Version | Status | Introduced | Deprecated | Notes |
|---|---|---|---|---|
| 14 | active | — | — | — |
Root Cause
Server Actions can only transmit serializable plain objects across the server-client boundary. Class instances, Date objects, and ORM model objects must be converted to plain objects first.
genericWorkarounds
-
92% success Use structuredClone() or explicit field picking to create plain objects
structuredClone(obj) creates a deep plain copy that preserves Dates, Maps, Sets, and ArrayBuffers. For Prisma/ORM models: select only the plain fields you need. Example: const plain = { id: user.id, name: user.name, createdAt: user.createdAt.toISOString() }.Sources: https://developer.mozilla.org/en-US/docs/Web/API/structuredClone
-
90% success Use Zod schema to serialize/deserialize at the server action boundary
Define a Zod schema for the data shape. Use .parse() on both the client (before sending) and server (in the action). This is the recommended Next.js pattern for type-safe server actions with complex data.
Sources: https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations
-
95% success Convert Date objects to ISO strings before passing to server actions
Call date.toISOString() on the client side before passing to the server action. Parse back with new Date(isoString) inside the action. This is the simplest fix for the most common variant of this error.
Dead Ends
Common approaches that don't work:
-
Using JSON.parse(JSON.stringify(obj)) to strip the class
65% fail
Loses Date objects (become strings), undefined values (become null or disappear), Map/Set (become empty objects), BigInt (throws), and Symbol/Function properties. Seems to work in simple cases but silently corrupts data in production.
-
Converting everything to FormData to bypass serialization
72% fail
FormData only supports string and Blob values. Nested objects, arrays, numbers, and booleans are all lost or coerced to strings. It works for simple forms but breaks for complex structured data.