leptos-rs/leptos · error
missing <head> element
Error message
missing <head> element
What it means
MetaContext::default builds a cursor positioned at the head-marker comment inside <head> so metadata can be injected during hydration. It unwraps document().head(), panicking with "missing <head> element" if the current document has no <head>. The library assumes a well-formed HTML document exists when leptos_meta runs on the client.
Source
Thrown at meta/src/lib.rs:122
pub(crate) cursor: Arc<LazyLock<SendWrapper<Cursor>>>,
}
impl MetaContext {
/// Creates an empty [`MetaContext`].
pub fn new() -> Self {
Default::default()
}
}
pub(crate) const HEAD_MARKER_COMMENT: &str = "HEAD";
/// Return value of [`Node::node_type`] for a comment.
/// https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType#node.comment_node
const COMMENT_NODE: u16 = 8;
impl Default for MetaContext {
fn default() -> Self {
let build_cursor: fn() -> SendWrapper<Cursor> = || {
let head = document().head().expect("missing <head> element");
let mut cursor = None;
let mut child = head.first_child();
while let Some(this_child) = child {
if this_child.node_type() == COMMENT_NODE
&& this_child.text_content().as_deref()
== Some(HEAD_MARKER_COMMENT)
{
cursor = Some(this_child);
break;
}
child = this_child.next_sibling();
}
SendWrapper::new(Cursor::new(
cursor
.expect(
"no leptos_meta HEAD marker comment found. Did you \
include the <MetaTags/> component in the <head> of \
your server-rendered app?",View on GitHub (pinned to 32d20f6c9d)
Solutions
- Ensure the document being hydrated contains a <head> element (valid HTML shell).
- Create MetaContext only in browser environments where a full document exists.
- In tests, build the DOM with a <head> containing the <!--HEAD--> marker comment if you exercise meta hydration.
- Do not strip <head> from the served markup before hydration.
Example fix
<!-- before: shell missing head --> <body>...</body> <!-- after --> <head><!--HEAD--><title>app</title></head> <body>...</body>
Defensive patterns
Strategy: validation
Validate before calling
if document().head().is_none() {
console_error!("document has no <head>; leptos_meta unavailable");
return;
} Type guard
fn has_head() -> bool {
document().head().is_some()
} Prevention
- Include <head> (with the <!--HEAD--> marker when hydrating meta) in every served document.
- Create MetaContext only after DOM readiness in a real browser.
- Don't strip the head chunk from streamed SSR output.
When it happens
Trigger: Constructing MetaContext::default() (directly or via leptos_meta's provider/hydration path) when document().head() returns None — e.g. a document with no <head> section, or running in an environment with an incomplete DOM.
Common situations: Custom SSR shells that omit <head>, streaming responses where the head chunk was already consumed/removed, or test DOMs built without head elements.
Related errors
- there to be a <html> element
- lazy routes should not be used with hydrate_body(); use hydr
- failed to read hash file
- could not read manifest file
- body to exist
AI-assisted analysis of leptos-rs/leptos@32d20f6c9d (2026-09-01).
Data as JSON: /api/errors/f63480fdc91a65f1.
Report an issue: GitHub.