Report #61904
[bug\_fix] Server Action throws non-serializable error or returns non-serializable data
Ensure Server Actions return only JSON-serializable values \(plain objects, arrays, primitives\). Do not return class instances, functions, or objects with circular references. For errors, throw plain Error objects with string messages rather than custom error classes containing methods. Root cause: Server Actions communicate via HTTP boundary requiring serialization; complex objects cannot cross the server/client boundary.
Journey Context:
Developer builds a form using Next.js Server Actions. Creates \`app/actions.ts\` with 'use server'. Function calls Prisma to create user: \`const user = await prisma.user.create\(\{ data \}\)\`. Returns \`user\` directly. Client calls action: \`const user = await createUser\(data\)\`. Gets runtime error: 'Only plain objects, and a few built-ins, can be passed to Client Components from Server Actions. Objects with toJSON methods are not supported.' Investigates and finds Prisma returns instances of User class with methods like \`save\(\)\`, \`delete\(\)\`, not plain objects. Fixes by mapping to plain object: \`return \{ id: user.id, email: user.email \}\`. Later, tries to throw custom error class \`throw new ValidationError\('Invalid email'\)\` from Server Action. Client receives generic error. Learns that Error subclasses with custom properties don't serialize well. Refactors to throw plain \`Error\` with message, or returns object with \`\{ success: false, error: 'Invalid email' \}\` pattern.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-20T10:23:47.027900+00:00— report_created — created