{"record":{"id":"c138feedbfb137bb","repo":"leptos-rs/leptos","slug":"async-route-used-in-ssr","errorCode":null,"errorMessage":"async route used in SSR","messagePattern":"async route used in SSR","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"router/src/flat_router.rs","lineNumber":535,"sourceCode":"\n        // release URL lock\n        drop(current_url);\n\n        let view = match new_match {\n            None => (self.fallback)().into_any(),\n            Some(new_match) => {\n                let id = new_match.as_matched().to_string();\n                let (view, _) = new_match.into_view_and_child();\n                let view = owner\n                    .with(|| {\n                        provide_context(url);\n                        provide_context(params_memo);\n                        provide_context(Matched(ArcMemo::from(matched)));\n\n                        ScopedFuture::new(async move { view.choose().await })\n                    })\n                    .now_or_never()\n                    .expect(\"async route used in SSR\");\n                let view = MatchedRoute(id, view);\n                view.into_any()\n            }\n        };\n\n        OwnedView::new_with_owner(view, owner)\n    }\n}\n\nimpl<Loc, Defs, FalFn, Fal> RenderHtml for FlatRoutesView<Loc, Defs, FalFn>\nwhere\n    Loc: LocationProvider + Send,\n    Defs: MatchNestedRoutes + Send + 'static,\n    FalFn: FnOnce() -> Fal + Send + 'static,\n    Fal: RenderHtml + 'static,\n{\n    type AsyncOutput = Self;\n    type Owned = Self;","sourceCodeStart":517,"sourceCodeEnd":553,"githubUrl":"https://github.com/leptos-rs/leptos/blob/32d20f6c9d517451d77beb68d88c7716823dac41/router/src/flat_router.rs#L517-L553","documentation":"In flat_router.rs, SSR rendering polls the async route view future with `.now_or_never()`, which only works if the future completes on its first poll. If the route's `choose()` awaits anything (e.g. a lazy-loaded async route component) and does not resolve immediately, the `expect` panics with \"async route used in SSR\". The router requires SSR route views to be synchronously resolvable; async routes are only supported in the browser where lazy loading can actually happen.","triggerScenarios":"Rendering a route defined with an async component / `AsyncProp` / lazy-loaded `#[component(async)]`-style view through `to_html_with_buf` or `to_html_async_with_buf` in a flat router; any `.await` inside the route's view function during server-side rendering.","commonSituations":"Server-rendering an app where routes were converted to async routes for browser-side lazy loading; copying a client-only example (which awaits data or dynamic imports) into an SSR setup; using code-splitting/lazy route loading without realizing it is unsupported on the server.","solutions":["Make the route's view/component resolve synchronously on the server: avoid `.await` in the view and load data instead via `<Suspense>` with a blocking resource.","Move lazy loading client-side only (e.g. gate dynamic loading behind `is_server()`/cfg so the server uses the already-loaded component).","Ensure blocking resources are used for async data so routes are available before render, matching the router's requirement that loaders/views be sync on the server."],"exampleFix":"// before\n#[component]\nasync fn Profile() -> impl IntoView {\n    let data = load_profile().await;\n    view! { <p>{data.name}</p> }\n}\n\n// after\n#[component]\nfn Profile() -> impl IntoView {\n    let data = Resource::new(|| (), |_| load_profile());\n    view! {\n      <Suspense fallback=|| ()>\n        {move || Suspend::new(async move { let d = data.await; view! { <p>{d.name}</p> } })}\n      </Suspense>\n    }\n}","handlingStrategy":"validation","validationCode":"// Before SSR, assert no route view awaits:\nif is_server() && routes.iter().any(|r| r.is_async()) {\n    panic!(\"async route detected in SSR; use blocking Suspense instead\");\n}","typeGuard":"fn is_ssr_safe(route: &RouteDef) -> bool { !route.is_async() || cfg!(feature = \"ssr\") == false }","tryCatchPattern":null,"preventionTips":["Never `.await` inside route view components; use blocking resources with <Suspense>.","Gate lazy loading behind is_server()/cfg so server builds get eager routes.","Test SSR rendering in CI so async-only routes fail at build/test time, not in production."],"tags":["ssr","async-route","router","leptos"],"backgroundTag":"async-route-in-ssr","analyzedSha":"32d20f6c9d517451d77beb68d88c7716823dac41","analyzedAt":"2026-09-01T18:55:42.580Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T01:17:15.007Z"}