remix-run/react-router · critical · Error
Invalid payload type
Error message
Invalid payload type
What it means
`createRouterFromPayload` bootstraps the client-side DataRouter from the initial RSC stream and only knows how to build a router from a payload of `type: "render"`. If the payload handed to it is any other type (action, redirect, manifest), it throws immediately. The render payload is normally produced by the framework's server entry; seeing this error means the initial payload was generated or routed incorrectly.
Source
Thrown at packages/react-router/lib/rsc/browser.tsx:276
payload,
}: {
payload: RSCPayload;
createFromReadableStream: BrowserCreateFromReadableStreamFunction;
fetchImplementation: (request: Request) => Promise<Response>;
getContext: RouterInit["getContext"] | undefined;
}): {
router: DataRouter;
routeModules: RouteModules;
} {
const globalVar = window as WindowWithRouterGlobals;
if (globalVar.__reactRouterDataRouter && globalVar.__reactRouterRouteModules)
return {
router: globalVar.__reactRouterDataRouter,
routeModules: globalVar.__reactRouterRouteModules,
};
if (payload.type !== "render") throw new Error("Invalid payload type");
let { clientVersion } = payload;
globalVar.__reactRouterRouteModules =
globalVar.__reactRouterRouteModules ?? {};
populateRSCRouteModules(globalVar.__reactRouterRouteModules, payload.matches);
let routes = payload.matches.reduceRight((previous, match) => {
const route: DataRouteObject = createRouteFromServerManifest(
match,
payload,
);
if (previous.length > 0) {
route.children = previous;
} else if (!route.index) {
route.children = [];
}
return [route];View on GitHub (pinned to 7aea711dd1)
Solutions
- Ensure the initial hydration request is served the framework's render payload (same URL, `React-Router-Resource`/RSC negotiation intact).
- If you cache RSC payloads at the edge, key them by request type so render, manifest, and action payloads are never interchanged.
- In custom entries, pass the payload received for the document request directly to `RSCHydratedRouter`, not one from an action/manifest fetch.
- Regenerate any recorded payload fixtures with the current version.
Defensive patterns
Strategy: type-guard
Validate before calling
if (payload.type !== "render") {
throw new Error("Cannot hydrate: expected render payload");
}
const { router } = createRouterFromPayload({ payload, ... }); Type guard
type RenderPayload = Extract<RSCPayload, { type: "render" }>;
const isRenderPayload = (p: RSCPayload): p is RenderPayload => p.type === "render"; Prevention
- Hydrate only from the payload of the initial document request.
- Cache RSC payloads keyed by request kind (render/manifest/action) at the edge.
- Refresh recorded payload fixtures on every React Router upgrade.
When it happens
Trigger: Passing a non-render payload (e.g., a manifest or action response captured from another request) into the hydration path via a custom `RSCHydratedRouter`/`createRouterFromPayload` usage; a custom server answering the initial document request with a redirect/action payload instead of the render stream; test harnesses reusing a stale payload fixture.
Common situations: Writing custom RSC server entries or playgrounds that fetch the wrong endpoint for hydration; integration tests hydrating from a recorded action response; edge workers that cache an RSC payload of the wrong type for the document URL.
Related errors
- Missing body in server response
- Unexpected payload type
- SPA Mode: Did you forget to include `<Scripts/>` in your roo
- The "@vitejs/plugin-rsc" plugin should be placed after the R
- When using the React Router `basename` and the Vite `base` c
AI-assisted analysis of remix-run/react-router@7aea711dd1 (2026-08-18).
Data as JSON: /api/errors/fa31a3879ee269d5.
Report an issue: GitHub.