remix-run/react-router · error
getRequest must be called from within a React Server render…
Error message
getRequest must be called from within a React Server render context
What it means
In RSC mode, getRequest() reads the current Request from an AsyncLocalStorage store populated while the RSC server handles the request. Outside that scope there is no store, so getRequest() (lib/rsc/server.rsc.ts:98) throws to tell you it was called detached from any server render context.
Solutions
- Call getRequest() only inside loaders/actions/middleware or during RSC render
- Thread the request explicitly (args.request) into helpers rather than using the global accessor
- Capture getRequest() early in the same async scope and close over the result before detaching async work
Example fix
// before
async function logPath() { console.log(getRequest().url) }
setTimeout(() => logPath(), 100) // throws: no store
// after
const url = getRequest().url // inside the loader
setTimeout(() => console.log(url), 100) Defensive patterns
Strategy: fallback
Validate before calling
// Prefer explicit threading; when you must use the global, verify scope first
function currentRequest(): Request | null {
try { return getRequest() } catch { return null }
}
const req = currentRequest() ?? explicitRequestArg; // caller-supplied fallback Try / catch
try {
const request = getRequest();
} catch (e) {
if (e instanceof Error && e.message.includes('React Server render context')) {
// no request scope: skip request-scoped work or require the request as a parameter
} else throw e;
} Prevention
- Pass args.request explicitly into helpers instead of global accessors
- Only call getRequest() inside loaders/actions/middleware or RSC render
- Capture request data before detaching async work (setTimeout, queues)
When it happens
Trigger: Calling getRequest() at module scope or during server startup; inside setTimeout/queueMicrotask/setImmediate callbacks that outlived the request context; in a helper invoked from a custom route handler outside the RSC pipeline; after awaiting something that swaps the async context.
Common situations: Logging/metrics helpers that 'grab' the request globally instead of receiving it; background jobs kicked off from a server action; refactoring loaders to use a global request accessor.
Related errors
- Cannot handle enhanced server action without decodeReply…
- Cannot handle form actions without a decodeAction function
- Error splitting route module
- Failed to clone server response
- Failed to patch routes
AI-assisted analysis of remix-run/react-router@7aea711dd1 (2026-08-18).
Data as JSON: /api/errors/298324e4343e21d0.
Report an issue: GitHub.
Appendix: source
Thrown at packages/react-router/lib/rsc/server.rsc.ts:98
type ServerContext = {
redirect?: Response;
request: Request;
runningAction: boolean;
};
const globalVar = (typeof globalThis !== "undefined" ? globalThis : global) as {
___reactRouterServerStorage___?: AsyncLocalStorage<ServerContext>;
};
const ServerStorage = (globalVar.___reactRouterServerStorage___ ??=
new AsyncLocalStorage<ServerContext>());
export function getRequest() {
const ctx = ServerStorage.getStore();
if (!ctx)
throw new Error(
"getRequest must be called from within a React Server render context",
);
return ctx.request;
}
export const redirect: typeof baseRedirect = (...args) => {
const response = baseRedirect(...args);
const ctx = ServerStorage.getStore();
if (ctx && ctx.runningAction) {
ctx.redirect = response;
}
return response;
};
export const redirectDocument: typeof baseRedirectDocument = (...args) => {
const response = baseRedirectDocument(...args);View on GitHub (pinned to 7aea711dd1)