DioxusLabs/dioxus · error
A router must be present to use navigator
Error message
A router must be present to use navigator
What it means
navigator() acquires the RouterContext that a Router component provides to its subtree. Without a Router ancestor the context doesn't exist, try_consume_context returns None, and the expect panics. Unlike a hook, navigator() may be called from anywhere inside RSX or event handlers, but still only under a mounted Router.
Source
Thrown at packages/router/src/contexts/navigator.rs:13
use crate::{ExternalNavigationFailure, NavigationTarget, RouterContext};
/// Acquire the navigator without subscribing to updates.
///
/// Can be called anywhere in the application provided a Router has been initialized.
///
/// ## Panics
///
/// Panics if there is no router present.
pub fn navigator() -> Navigator {
Navigator(
dioxus_core::try_consume_context::<RouterContext>()
.expect("A router must be present to use navigator"),
)
}
/// A view into the navigation state of a router.
#[derive(Clone, Copy)]
pub struct Navigator(pub(crate) RouterContext);
impl Navigator {
/// Check whether there is a previous page to navigate back to.
#[must_use]
pub fn can_go_back(&self) -> bool {
self.0.can_go_back()
}
/// Check whether there is a future page to navigate forward to.
#[must_use]
pub fn can_go_forward(&self) -> bool {
self.0.can_go_forward()View on GitHub (pinned to 393d190a80)
Solutions
- Wrap your app in a Router: define #[derive(Routable)] enum Route and launch the router (Router::<Route> {})
- If a component must work with or without a router, gate the call: check try_consume_context::<RouterContext>() first
- For optional navigation, fall back to staying on the current view when the context is absent
Example fix
// before
rsx! { button { onclick: move |_| navigator().push("/settings"), "Go" } } // no Router mounted
// after
#[derive(Clone, Routable)]
enum Route { #[route("/settings")] Settings {}, #[route("/")] Home {} }
// root component:
rsx! { Router::<Route> {} } Defensive patterns
Strategy: type-guard
Validate before calling
if dioxus::prelude::try_consume_context::<dioxus::router::RouterContext>().is_some() {
let nav = dioxus::router::navigator();
nav.push("/settings");
} else {
// no router mounted: fall back (inert link, no-op, or render Router first)
} Type guard
fn router_present() -> bool {
dioxus::prelude::try_consume_context::<dioxus::router::RouterContext>().is_some()
} Prevention
- Mount Router::<Route> {} once at the app root before using any navigation API
- In shared/library components, check for the RouterContext before calling navigator()
- Keep navigation calls inside the RSX tree of a routed app
When it happens
Trigger: Calling navigator() in a tree that never mounts a Router (plain dioxus::launch(Component) app, LaunchBuilder without a Routable root), or invoking it in a context outside the component tree (background tasks, server code).
Common situations: Adding navigator().push(...) navigation to a small demo or test app that has no router set up; refactoring a component out of a routed app into a library; calling navigator in code paths that also run on the server.
Related errors
- Outlet must be inside of a router
- Must be called in a descendant of a Router component
- use_route must have access to a router
- access to `window`
- `history` can set scroll restoration
AI-assisted analysis of DioxusLabs/dioxus@393d190a80 (2026-08-16).
Data as JSON: /api/errors/8f495545b085f504.
Report an issue: GitHub.