remix-run/react-router · error · Error
Unexpected payload type
Error message
Unexpected payload type
What it means
After invoking a server action, the RSC client decodes the returned payload and requires its `type` to be `"action"` (with `actionResult`) or `"redirect"`. Anything else — typically a `"render"` navigation payload or a `"manifest"` payload — throws this error. It almost always means the POST was not processed as an action call by the server, so the shape the client got does not match the action protocol.
Source
Thrown at packages/react-router/lib/rsc/browser.tsx:246
),
errors: rerender.errors
? Object.assign(
{},
globalVar.__reactRouterDataRouter.state.errors,
rerender.errors,
)
: null,
},
);
});
}
})
.catch(() => {}),
);
return payloadPromise.then((payload) => {
if (payload.type !== "action" && payload.type !== "redirect") {
throw new Error("Unexpected payload type");
}
return payload.actionResult;
});
};
}
function createRouterFromPayload({
fetchImplementation,
createFromReadableStream,
getContext,
payload,
}: {
payload: RSCPayload;
createFromReadableStream: BrowserCreateFromReadableStreamFunction;
fetchImplementation: (request: Request) => Promise<Response>;
getContext: RouterInit["getContext"] | undefined;
}): {View on GitHub (pinned to 7aea711dd1)
Solutions
- Verify the `rsc-action-id` request header survives every proxy/CDN/service-worker hop and reaches your server.
- Rule out version skew: hard reload after deploys, and keep client/server built from the same artifact.
- If you have a custom server, ensure requests with `rsc-action-id` are handled by the RSC action pipeline, not the document/SSR pipeline.
- Log the received payload `type` temporarily to identify which interceptor is changing the response.
Defensive patterns
Strategy: try-catch
Try / catch
try {
await submitServerAction();
} catch (e) {
if (e instanceof Error && e.message === "Unexpected payload type") {
window.location.reload(); // typically version skew after a deploy
} else {
throw e;
}
} Prevention
- Preserve the rsc-action-id header across every proxy hop.
- Deploy client and server together; prompt reload on version change.
- Route rsc-action-id requests to the RSC handler in custom servers.
When it happens
Trigger: A proxy or service worker stripping the `rsc-action-id` header, so the server treats the request as a normal navigation and returns a render payload; version skew where an old client sends action ids a new server no longer resolves to actions; custom servers routing RSC POSTs to the wrong handler.
Common situations: Reverse proxies (nginx/Cloudflare workers) dropping custom headers; auth layers that redirect POSTs into GET navigations; mid-deploy requests where client and server action manifests disagree.
Related errors
- No response body
- Invalid payload type
- You are trying to call ${fn} on a route that does not have a
- Failed to patch routes
- The "@vitejs/plugin-rsc" plugin should be placed after the R
AI-assisted analysis of remix-run/react-router@7aea711dd1 (2026-08-18).
Data as JSON: /api/errors/444413139b1d15c1.
Report an issue: GitHub.