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

  1. Call getRequest() only inside loaders/actions/middleware or during RSC render
  2. Thread the request explicitly (args.request) into helpers rather than using the global accessor
  3. 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

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


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)