Everyone can type "use client". Almost nobody can say what survives the trip across it — and then something breaks: next build dies at prerender, the error names no file and no import chain, and the prop that killed it was an arrow one level down inside an object called options.

Here's the uncomfortable secret: the boundary is one serializer. React walks every prop you hand a client component, encodes each value it has a branch for, and throws on the first one it doesn't. This post reads those branches out of React 19's Flight source — one file, no framework — and shows the two traps that pass code review and fail the build anyway.

What crosses

A prop is legal if the serializer has a branch for it. Everything else falls into one prototype check and throws. The whole contract fits on a screen:

// app/page.tsx — a Server Component. Every comment is the serializer's verdict.