DioxusLabs/dioxus · error

Body element to exist

Error message

Body element to exist

What it means

The desktop protocol injects its JS module loader immediately before `</body>`; find("</body>").expect("Body element to exist") panics when the served index.html has no exact closing body tag. Unlike the head check, this runs on every root request regardless of custom_head.

Source

Thrown at packages/desktop/src/protocol.rs:129

    // If the request is for the root, we'll serve the index.html file.
    if request.uri().path() != "/" {
        return None;
    }

    // Load a custom index file if provided
    let mut index = custom_index.unwrap_or_else(|| DEFAULT_INDEX.to_string());

    // Insert a custom head if provided
    // We look just for the closing head tag. If a user provided a custom index with weird syntax, this might fail
    if let Some(head) = custom_head {
        index.insert_str(index.find("</head>").expect("Head element to exist"), &head);
    }

    // Inject our module loader by looking for a body tag
    // A failure mode here, obviously, is if the user provided a custom index without a body tag
    // Might want to document this
    index.insert_str(
        index.find("</body>").expect("Body element to exist"),
        &module_loader(root_name, headless, edit_state),
    );

    Response::builder()
        .header("Content-Type", "text/html")
        .header("Access-Control-Allow-Origin", "*")
        .body(index.into())
        .ok()
}

/// Construct the inline script that boots up the page and bridges the webview with rust code.
///
/// The arguments here:
/// - root_name: the root element (by Id) that we stream edits into
/// - headless: is this page being loaded but invisible? Important because not all windows are visible and the
///   interpreter can't connect until the window is ready.
/// - port: the port that the websocket server is listening on for edits
/// - webview_id: the id of the webview that we're loading this into. This is used to differentiate between

View on GitHub (pinned to 393d190a80)

Solutions

  1. Include a complete HTML document with `<body>...</body>` in the custom index
  2. Ensure the literal lowercase `</body>` is present; the lookup is case-sensitive
  3. Remove the custom index to fall back to dioxus's built-in default index

Example fix

// before
.with_custom_index("<div id='main'></div>".into())

// after
.with_custom_index("<!DOCTYPE html><html><head></head><body><div id='main'></div></body></html>".into())
Defensive patterns

Strategy: validation

Validate before calling

fn index_has_body(index: &str) -> bool { index.contains("</body>") }

let html = std::fs::read_to_string("index.html").unwrap();
assert!(index_has_body(&html), "custom index must contain </body>");

Type guard

fn is_valid_custom_index(index: &str) -> bool {
    index.contains("</body>") && index.contains("</head>")
}

Prevention

When it happens

Trigger: Supplying a custom index via with_custom_index (or the configured index.html) that lacks `</body>` - e.g. only a fragment like `<div id="main"></div>` - or uses a case-mismatched `</BODY>`.

Common situations: Replacing index.html with a partial snippet; minified/templated HTML where the body tag got mangled; assuming the framework will wrap fragments automatically.

Related errors


AI-assisted analysis of DioxusLabs/dioxus@393d190a80 (2026-08-16). Data as JSON: /api/errors/512cdb657280f25d. Report an issue: GitHub.