remix-run/react-router · error

You cannot use navigator.go() on the server because it is a

Error message

You cannot use navigator.go() on the server because it is a stateless environment. This error was probably triggered when you did a `navigate(${delta})` somewhere in your app.

What it means

History jumps like navigate(-1) or navigate(2) map to navigator.go(delta), which throws on the SSR stateless navigator (lib/dom/server.tsx:283). A server render has no browser history stack to traverse, so any relative jump executed server-side is a bug.

Source

Thrown at packages/react-router/lib/dom/server.tsx:312

    createHref,
    encodeLocation,
    push(to: To) {
      throw new Error(
        `You cannot use navigator.push() on the server because it is a stateless ` +
          `environment. This error was probably triggered when you did a ` +
          `\`navigate(${JSON.stringify(to)})\` somewhere in your app.`,
      );
    },
    replace(to: To) {
      throw new Error(
        `You cannot use navigator.replace() on the server because it is a stateless ` +
          `environment. This error was probably triggered when you did a ` +
          `\`navigate(${JSON.stringify(to)}, { replace: true })\` somewhere ` +
          `in your app.`,
      );
    },
    go(delta: number) {
      throw new Error(
        `You cannot use navigator.go() on the server because it is a stateless ` +
          `environment. This error was probably triggered when you did a ` +
          `\`navigate(${delta})\` somewhere in your app.`,
      );
    },
    back() {
      throw new Error(
        `You cannot use navigator.back() on the server because it is a stateless ` +
          `environment.`,
      );
    },
    forward() {
      throw new Error(
        `You cannot use navigator.forward() on the server because it is a stateless ` +
          `environment.`,
      );
    },
  };

View on GitHub (pinned to 7aea711dd1)

Solutions

  1. Trigger delta navigation only from real user events (onClick), never during render or mount
  2. For logical back navigation, track an explicit route (from a query param or referrer) and use loader redirect instead
  3. Guard with an isBrowser check if the same code path can run on the server

Example fix

// before (runs on server render)
const navigate = useNavigate()
if (!search) navigate(-1)
// after (event-only)
<button onClick={() => navigate(-1)}>Go back</button>
Defensive patterns

Strategy: validation

Validate before calling

const isServer = typeof window === 'undefined';
function goBack(navigate: NavigateFunction) {
  if (isServer) return; // never jump history during SSR
  navigate(-1);
}

Prevention

When it happens

Trigger: A back button implemented as <button onClick={...}> whose handler also runs during SSR render; navigate(-1) invoked in a component body or layout effect that executes on the server; shared components calling history-relative navigation on mount.

Common situations: 'Go back' UI rendered on the server that eagerly navigates; mobile-style flows using delta navigation on first render; effects ported from client-only apps into SSR components.

Related errors


AI-assisted analysis of remix-run/react-router@7aea711dd1 (2026-08-18). Data as JSON: /api/errors/fc8410281ce2b6c5. Report an issue: GitHub.