{"record":{"id":"e6125e0fcfa8eb5c","repo":"DioxusLabs/dioxus","slug":"failed-to-parse-index-html-from-public-directory","errorCode":null,"errorMessage":"Failed to parse index.html from public directory","messagePattern":"Failed to parse index\\.html from public directory","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/fullstack-server/src/config.rs","lineNumber":64,"sourceCode":"    }\n\n    /// Create a new ServeConfig with incremental static generation disabled and the default index.html settings\n    ///\n    /// This will automatically use the `index.html` file in the `/public` directory if it exists.\n    /// The `/public` folder is meant located next to the current executable. If no `index.html` file is found,\n    /// a default index.html will be used, which will not include any JavaScript or WASM initialization code.\n    ///\n    /// To provide an alternate `index.html`, you can use `with_index_html` method instead.\n    pub fn new() -> Self {\n        let index = if let Some(public_path) = crate::public_path() {\n            let index_html_path = public_path.join(\"index.html\");\n\n            if index_html_path.exists() {\n                let index_html = std::fs::read_to_string(index_html_path)\n                    .expect(\"Failed to read index.html from public directory\");\n\n                IndexHtml::new(&index_html, \"main\")\n                    .expect(\"Failed to parse index.html from public directory\")\n            } else {\n                IndexHtml::ssr_only()\n            }\n        } else {\n            tracing::warn!(\n                \"Cannot identify public directory, using default index.html. If you need client-side scripts (like JS + WASM), please provide an explicit public directory.\"\n            );\n            IndexHtml::ssr_only()\n        };\n\n        Self {\n            index,\n            incremental: None,\n            context_providers: Default::default(),\n            streaming_mode: StreamingMode::default(),\n        }\n    }\n","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/DioxusLabs/dioxus/blob/393d190a801ccb441d41923e232289b4f8a5c669/packages/fullstack-server/src/config.rs#L46-L82","documentation":"Thrown by the fullstack server during ServeConfig::new() when a public/index.html exists but IndexHtml::new cannot parse it. The parser is a naive string splitter that requires a literal id=\"main\" attribute (the hardcoded root id), a > closing that tag, a </head> tag before the root element, a </body> tag after it, and a closed <title> pair. Any missing marker makes IndexHtml::new return Err, which config.rs unwraps with expect, aborting server startup.","triggerScenarios":"Launching a fullstack app (dioxus::launch / LaunchBuilder with a server) where <crate>/public/index.html exists but: the root element has a different id (id=\"root\", id=\"app\"), </head> or </body> tags were removed/reordered, the id=\"main\" attribute is not followed by >, or a <title> tag is unclosed.","commonSituations":"Porting an index.html from a Vite/React template that uses id=\"root\"; hand-minified HTML with dropped closing tags; changing the root id in Dioxus.toml while the fullstack server still looks for id=\"main\"; malformed HTML from a custom build step.","solutions":["Add <div id=\"main\"></div> inside <body> as the app root container","Ensure a literal </head> appears before the root div and a literal </body> appears after it","Close the title element: <title>...</title>","If you don't need a custom shell, remove/rename index.html so the server falls back to IndexHtml::ssr_only()","If you need a different root id, pass a valid document via ServeConfig::with_index_html instead"],"exampleFix":"// before (public/index.html)\n<html><head><title>App</title><body><div id=\"root\"></div></body></html>\n// after\n<html><head><title>App</title></head><body><div id=\"main\"></div></body></html>","handlingStrategy":"validation","validationCode":"fn index_html_is_parsable(public_dir: &std::path::Path) -> bool {\n    let Ok(html) = std::fs::read_to_string(public_dir.join(\"index.html\")) else {\n        return false; // server falls back to ssr_only\n    };\n    let (_, post_main) = html.split_once(\"id=\\\"main\\\"\").unwrap_or((\"\", \"NONEMAIN\"));\n    html.split_once(\"id=\\\"main\\\"\").is_some()\n        && post_main.split_once('>').is_some()\n        && html.split_once(\"</head>\").is_some()\n        && html.split_once(\"</body>\").is_some()\n        && !(html.contains(\"<title>\") && !html.contains(\"</title>\"))\n}\n// assert!(index_html_is_parsable(Path::new(\"public\"))) before building the server","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep a CI check that validates public/index.html contains id=\\\"main\\\", </head> and </body>","Treat the default generated index.html as the template and only add elements inside it","If you change the root id in Dioxus.toml, remember the fullstack server path still expects id=\\\"main\\\" unless you use with_index_html"],"tags":["fullstack","server","index-html","config","startup","panic"],"backgroundTag":null,"analyzedSha":"393d190a801ccb441d41923e232289b4f8a5c669","analyzedAt":"2026-08-16T11:27:45.815Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}