ionic-team/ionic-framework · error · Error

An Ionic Router is required for IonRouterContext

Error message

An Ionic Router is required for IonRouterContext

What it means

This is the default `push` function on the IonRouterContext created by `React.createContext`. It exists only as a placeholder so that TypeScript is satisfied and so that calling the hook outside a provider fails loudly instead of silently no-op'ing. It throws when `useIonRouter().push(...)` is invoked but no `<IonReactRouter>` ancestor supplied a real context value.

Source

Thrown at packages/react/src/components/IonRouterContext.tsx:24

export interface IonRouterContextState {
  routeInfo: RouteInfo;
  push: (
    pathname: string,
    routerDirection?: RouterDirection,
    routeAction?: RouteAction,
    routerOptions?: RouterOptions,
    animationBuilder?: AnimationBuilder
  ) => void;
  back: (animationBuilder?: AnimationBuilder) => void;
  canGoBack: () => boolean;
  nativeBack: () => void;
}

export const IonRouterContext = React.createContext<IonRouterContextState>({
  routeInfo: undefined as any, // TODO(FW-2959): type
  push: () => {
    throw new Error('An Ionic Router is required for IonRouterContext');
  },
  back: () => {
    throw new Error('An Ionic Router is required for IonRouterContext');
  },
  canGoBack: () => {
    throw new Error('An Ionic Router is required for IonRouterContext');
  },
  nativeBack: () => {
    throw new Error('An Ionic Router is required for IonRouterContext');
  },
});

/**
 * A hook for more direct control over routing in an Ionic React application. Allows you to pass additional meta-data to the router before the call to the native router.
 */
export function useIonRouter(): UseIonRouterResult {
  const context = useContext(IonRouterContext);

View on GitHub (pinned to 625f9c38ad)

Solutions

  1. Ensure the component using `useIonRouter()` is rendered inside `<IonReactRouter>` (which provides the real IonRouterContext value).
  2. In tests, wrap the component under test with `<IonReactRouter><Route>...</Route></IonReactRouter>` (or the app's full router setup).
  3. Move portals/modals that need routing inside the router tree, or pass router actions down via props instead.
  4. Confirm the provider is mounted before the consumer — check for conditional/suspense boundaries that delay the provider.

Example fix

// before
function MyLink() {
  const router = useIonRouter();
  return <button onClick={() => router.push('/x')}>Go</button>;
}
// <App> renders <MyLink /> outside <IonReactRouter>

// after
<IonReactRouter>
  <IonRouterOutlet>
    <Route path="/" component={MyLink} />
  </IonRouterOutlet>
</IonReactRouter>
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the consumer is inside <IonReactRouter> before calling push
import { IonRouterContext } from '@ionic/react';
import { useContext } from 'react';
const ctx = useContext(IonRouterContext);
// The default context's push throws; detect a missing provider by checking routeInfo
if (ctx.routeInfo === undefined) {
  throw new Error('useIonRouter() must be used inside <IonReactRouter>.');
}
ctx.push('/path');

Type guard

function hasIonicRouter(ctx: IonRouterContextState): boolean {
  return ctx.routeInfo !== undefined;
}

Prevention

When it happens

Trigger: Calling `const router = useIonRouter(); router.push('/path')` in a React component that is rendered outside the `<IonReactRouter>` provider tree, so `useContext(IonRouterContext)` returns the default object whose `push` throws.

Common situations: Using `useIonRouter()` in a layout, modal, portal, or dev-tools panel rendered outside `<IonReactRouter>`; testing a component in isolation without wrapping it in `<IonReactRouter>`; conditional rendering that mounts the component before the router.

Related errors


AI-assisted analysis of ionic-team/ionic-framework@625f9c38ad (2026-08-12). Data as JSON: /api/errors/8810b2311f690457. Report an issue: GitHub.