leptos-rs/leptos · error
there to be a <body> element
Error message
there to be a <body> element
What it means
Leptos' <body> meta component (tachys RenderHtml impl) builds by fetching document().body() via web_sys. In a non-DOM or pre-DOM environment this is None, and expect('there to be a <body> element') panics. The library assumes the code runs in a browser after the document body exists.
Source
Thrown at meta/src/body.rs:70
struct BodyView<At> {
attributes: At,
}
struct BodyViewState<At>
where
At: Attribute,
{
attributes: At::State,
}
impl<At> Render for BodyView<At>
where
At: Attribute,
{
type State = BodyViewState<At>;
fn build(self) -> Self::State {
let el = document().body().expect("there to be a <body> element");
let attributes = self.attributes.build(&el);
BodyViewState { attributes }
}
fn rebuild(self, state: &mut Self::State) {
self.attributes.rebuild(&mut state.attributes);
}
}
impl<At> AddAnyAttr for BodyView<At>
where
At: Attribute,
{
type Output<SomeNewAttr: Attribute> =
BodyView<<At as NextAttribute>::Output<SomeNewAttr>>;
fn add_any_attr<NewAttr: Attribute>(View on GitHub (pinned to 32d20f6c9d)
Solutions
- Ensure the code only runs in a browser context after the DOM is ready (e.g. inside on_mount or after DOMContentLoaded).
- Guard with a check: if document().body().is_none() return early instead of building the Body component.
- For tests, run in a wasm browser test harness (wasm-bindgen-test) rather than native cargo test.
Example fix
// before
let body = document().body().expect("there to be a <body> element");
// after
let Some(body) = document().body() else { return; }; Defensive patterns
Strategy: validation
Validate before calling
use wasm_bindgen::JsCast;
fn has_body() -> bool {
web_sys::window().map(|w| w.document()).flatten()
.map(|d| d.body().is_some())
.unwrap_or(false)
} Type guard
fn get_body() -> Option<web_sys::HtmlElement> {
web_sys::window()?.document()?.body()
} Try / catch
// leptos panics are not catchable; check before mounting
if has_body() {
mount_to_body(App);
} else {
leptos::logging::error!("document body not available");
} Prevention
- Mount only after DOMContentLoaded or from a script at end of <body>
- Never run DOM-dependent code in SSR or worker targets unguarded
- Use cfg(target_arch = "wasm32") gates for browser-only code paths
When it happens
Trigger: Calling .build() on leptos::prelude::Body (the <body> meta wrapper) when document().body() returns None — e.g. running in SSR/non-wasm stub, or executing before the HTML <body> tag has been parsed.
Common situations: Unit tests running wasm-dependent code without a DOM; scripts injected into <head> that run before <body> exists; executing hydration/mount logic inside a worker or server target.
Related errors
- there to be a <html> element
- body to exist
- SVG element creation to work
- HTML element creation to work
- missing <head> element
AI-assisted analysis of leptos-rs/leptos@32d20f6c9d (2026-09-01).
Data as JSON: /api/errors/64952a1f3f058d0c.
Report an issue: GitHub.