{"record":{"id":"45364a84a5ce174f","repo":"leptos-rs/leptos","slug":"you-cannot-use-suspend-on-an-attribute-outside-sus","errorCode":null,"errorMessage":"You cannot use Suspend on an attribute outside Suspense","messagePattern":"You cannot use Suspend on an attribute outside Suspense","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tachys/src/reactive_graph/class.rs","lineNumber":985,"sourceCode":"impl<Fut> IntoClass for Suspend<Fut>\nwhere\n    Fut: Clone + Future + Send + 'static,\n    Fut::Output: IntoClass,\n{\n    type AsyncOutput = Fut::Output;\n    type State = Rc<RefCell<Option<<Fut::Output as IntoClass>::State>>>;\n    type Cloneable = Self;\n    type CloneableOwned = Self;\n\n    fn html_len(&self) -> usize {\n        0\n    }\n\n    fn to_html(self, style: &mut String) {\n        if let Some(inner) = self.inner.now_or_never() {\n            inner.to_html(style);\n        } else {\n            panic!(\"You cannot use Suspend on an attribute outside Suspense\");\n        }\n    }\n\n    fn hydrate<const FROM_SERVER: bool>(\n        self,\n        el: &crate::renderer::types::Element,\n    ) -> Self::State {\n        let el = el.to_owned();\n        let state = Rc::new(RefCell::new(None));\n        reactive_graph::spawn_local_scoped({\n            let state = Rc::clone(&state);\n            async move {\n                *state.borrow_mut() =\n                    Some(self.inner.await.hydrate::<FROM_SERVER>(&el));\n                self.subscriber.forward();\n            }\n        });\n        state","sourceCodeStart":967,"sourceCodeEnd":1003,"githubUrl":"https://github.com/leptos-rs/leptos/blob/32d20f6c9d517451d77beb68d88c7716823dac41/tachys/src/reactive_graph/class.rs#L967-L1003","documentation":"An async (Suspend-wrapped) class attribute cannot produce its value synchronously. During server HTML string generation (to_html), the framework calls now_or_never(); if the future is not ready, rendering is outside a Suspense context that would otherwise await it, so it panics.","triggerScenarios":"Using Suspend (async-derived class value) as a class attribute while rendering to HTML (SSR/dry-run) without the attribute being inside a <Suspense> component.","commonSituations":"Making a class reactive/async in a component rendered during SSR but forgetting to wrap the view in Suspense; refactoring an attribute to an async source without updating the rendering context.","solutions":["Wrap the containing view in <Suspense> so the async attribute can be awaited during SSR.","Make the class value synchronous for the initial render (resolve the data before rendering, or use a sync signal).","If async data is required, move the async read inside a Suspense boundary or use await Suspending() in the component body (leptos)."],"exampleFix":"// before\nview! { <div class=Suspend(async move { load_class().await }) /> }\n// after\nview! {\n  <Suspense fallback=|| ()>\n    <div class=Suspend(async move { load_class().await }) />\n  </Suspense>\n}","handlingStrategy":"validation","validationCode":"fn ensure_suspense_context(rendering_to_html: bool, inside_suspense: bool) { if rendering_to_html && !inside_suspense { panic!(\"async class attribute requires a Suspense boundary\"); } }","typeGuard":"fn class_is_sync(c: &impl Fn() -> String) {} // prefer sync closures/signals over Suspend for attributes","tryCatchPattern":"std::panic::catch_unwind(|| view_to_html(&view)).map_err(|_| /* rebuild view inside Suspense */)","preventionTips":["Only use Suspend on attributes inside <Suspense>.","Prefer synchronous signals for class values in initial renders.","Move async data fetching above the component (resources awaited in Suspense).","Test SSR output locally to catch this before deploy."],"tags":["ssr","suspense","async-attribute"],"backgroundTag":"suspend-attribute-outside-suspense","analyzedSha":"32d20f6c9d517451d77beb68d88c7716823dac41","analyzedAt":"2026-09-01T18:55:42.580Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T01:17:15.007Z"}