{"record":{"id":"2a10e0933852a39b","repo":"leptos-rs/leptos","slug":"body-to-exist","errorCode":null,"errorMessage":"body to exist","messagePattern":"body to exist","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"leptos/src/portal.rs","lineNumber":40,"sourceCode":"    /// When using SVG this has to be set to `true`. Defaults to `false`.\n    #[prop(optional)]\n    is_svg: bool,\n    /// The children to teleport into the `mount` element\n    children: TypedChildrenFn<V>,\n) -> impl IntoView\nwhere\n    V: IntoView + 'static,\n{\n    if cfg!(target_arch = \"wasm32\")\n        && Owner::current_shared_context()\n            .map(|sc| sc.is_browser())\n            .unwrap_or(true)\n    {\n        use send_wrapper::SendWrapper;\n        use wasm_bindgen::JsCast;\n\n        let mount = mount.unwrap_or_else(|| {\n            document().body().expect(\"body to exist\").unchecked_into()\n        });\n        let children = children.into_inner();\n\n        Effect::new(move |_| {\n            let container = if is_svg {\n                document()\n                    .create_element_ns(Some(\"http://www.w3.org/2000/svg\"), \"g\")\n                    .expect(\"SVG element creation to work\")\n            } else {\n                document()\n                    .create_element(\"div\")\n                    .expect(\"HTML element creation to work\")\n            };\n\n            let render_root = if use_shadow {\n                container\n                    .attach_shadow(&web_sys::ShadowRootInit::new(\n                        web_sys::ShadowRootMode::Open,","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/leptos-rs/leptos/blob/32d20f6c9d517451d77beb68d88c7716823dac41/leptos/src/portal.rs#L22-L58","documentation":"The <Portal/> component mounts its children into a mount target element; when none is given it falls back to document().body().expect(\"body to exist\"). The panic means document.body was null when the Portal was created — the code is running in a DOM-less environment (SSR, or a script executed before <body> is parsed).","triggerScenarios":"Rendering <Portal/> without a mount prop during SSR; running client-side code from <head> before <body> exists; executing in a jsdom/test environment with no body attached.","commonSituations":"SSR hydration pass accidentally rendering Portal; scripts loaded with default (blocking) placement in <head>; wasm tests that never append a body to the document.","solutions":["Pass an explicit mount element to <Portal mount={...}/> so body is never needed.","Only render <Portal/> on the client, e.g. inside a component gated on a mounted signal or hydration completion.","Load your wasm script at the end of <body> or with defer so body exists.","In tests, ensure the fixture creates and attaches document.body."],"exampleFix":"// before\nview! { <Portal><div/>\"></Portal> } // SSR: body is None\n// after\nlet mount = document().get_element_by_id(\"app\");\nview! { <Portal mount={mount}><div/>\"></Portal> } // or gate on is_client\n","handlingStrategy":"validation","validationCode":"if document().body().is_none() {\n    // skip Portal or wait for client mount\n    return;\n}\n","typeGuard":"fn body_ready() -> bool { document().body().is_some() }\n","tryCatchPattern":null,"preventionTips":["Always pass an explicit mount element to <Portal/>","Load wasm scripts at end of <body> or with defer","Gate Portal rendering behind a client-mounted flag for SSR apps","In tests, create and attach document.body before rendering"],"tags":["leptos","dom","portal","ssr"],"backgroundTag":"document-body-missing","analyzedSha":"32d20f6c9d517451d77beb68d88c7716823dac41","analyzedAt":"2026-09-01T18:55:42.580Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T01:17:15.007Z"}